【问题标题】:how to access variables in closures if there are local variables with the same name?如果存在同名的局部变量,如何访问闭包中的变量?
【发布时间】:2010-08-13 06:42:18
【问题描述】:

我从 Google Code Playground http://code.google.com/apis/ajax/playground/ 获取了这个

/*CLOSURE
* When a function is defined in another function and it
*    has access to the outer function's context even after
*    the outer function returns
* An important concept to learn in Javascript
*/

function outerFunction(someNum) {
  var someString = 'Hai!';
  var content = document.getElementById('content');
  function innerFunction() {
    content.innerHTML = someNum + ': ' + someString;
    content = null; // IE memory leak for DOM reference
  }
  innerFunction();
}

outerFunction(1);

///////////////////////

没关系,但是如果我在内部函数中有一个与外部函数中的变量同名的局部变量,那么如何访问该变量?

function outerFunction(someNum) {
  var someString = 'Hai!';
  var content = document.getElementById('content');
  function innerFunction() {
    var someString='Hello';
    content.innerHTML = someNum + ': ' + someString;
    content = null; // IE memory leak for DOM reference
  }
  innerFunction();
}

outerFunction(1);

【问题讨论】:

标签: javascript


【解决方案1】:

你不能,因为外部作用域的变量被你内部函数上的变量所遮蔽

innerFunction 上的作用域链如下所示:

innerFunction externalFunction 全局对象 ____________ ______________ _______________ |* someString = '你好'| * 表示 innerFunction 范围内的可解析标识符。

每个函数都有自己的变量对象,是函数声明、变量声明和函数形式参数的标识符作为属性存在的地方。

这些对象不能被代码直接访问,作用域链是由所有这些链接的对象形成的。

当标识符为resolved时,查找在作用域链中向上,寻找它的第一个出现,直到到达全局对象,如果没有找到标识符,则抛出ReferenceError

看看以下文章:

【讨论】:

  • @Sriram - 更改变量名称,或将外部变量作为参数传入。
  • @CMS - 嗯 - 这是 Chrome:a.imageshack.us/img401/2914/chromez.jpg - 对我来说,在 FF 中看起来也差不多。
  • @CMS - 非常好;现在看起来很完美。
  • +1 感谢@CMS。正是我想要的。出于某种原因,我认为变量声明可能会影响形式参数(都在同一个函数中),但现在我看到它们都是同一个变量对象上的属性。现在可以理解为什么更改arguments[0] 也会更改与参数同名的变量。我更喜欢 strict mode 行为,我可以在不影响参数的情况下调整参数对象。再次感谢。
【解决方案2】:

闭包的局部变量“遮蔽”了外部函数的同名变量,所以这样:

function outerFunction(s) {
  var someString = 'Hai!';
  function innerFunction() {
    var someString='Hello';
    alert(someString);
  }
  innerFunction();
}
outerFunction();

will alert Hello.

解决此问题的唯一方法是重命名变量,或传入要使用的变量:

function outerFunction(s) {
  var someString = 'Hai!';
  function innerFunction(outer) {
    var someString='Hello';
    alert(outer);
  }
  innerFunction(someString);
}
outerFunction();        

Will alert Hai!

要了解作用域链,take a look at this previous scope question.

【讨论】:

    【解决方案3】:

    尝试使用 this.varname 来引用闭包中的那个。

    this.someString 在你的例子中。

    【讨论】:

    • this 变量的含义取决于内部函数的调用方式,因此只有在包含闭包作用域的函数是作为方法调用内部函数的上下文时才有效。如果你将该函数传递给其他对象然后调用它,即使闭包的链接仍然存在,this 也不会指向它。
    • 是的。我意识到这一点,正要删除我自己的答案,但你的解释让它值得留下。 :)
    • 你能再解释一下吗?我还没有得到“这个”的东西!
    • @Sriram,@Sebastián,看看this question
    【解决方案4】:

    你可以

    • 只需避免创建任何同名的局部变量,或者
    • 制作该闭包变量的本地副本声明同名的局部变量(如果你真的想要同名的局部变量)

    (有一个解决方法,但在指出它实际上不起作用后将其删除)

    【讨论】:

    • 你永远不会只调用外部的innerfunc()
    • copyofmyvar 将始终为 undefined,变量实例化过程发生在 实际函数执行之前,作用域中遇到的变量用 undefined 初始化,这发生在内部作用域中定义的myvar,被添加到变量对象并用undefined 初始化,稍后,函数执行并进行分配,到那时来自外部作用域的myvar 已经被遮蔽了。
    • 哦,谢谢,这意味着我猜我的大部分答案实际上都是错误的。
    • 不客气,您可以查看this question了解更多详情。 :)
    【解决方案5】:
    function outerFunction(someNum) {
    var someString = 'Hai!';
    var content = document.getElementById('content');
    function innerFunction() {
    this.someString = 'Hello'; 
    content.innerHTML = someNum + ': ' + someString;
    content = null; // IE memory leak for DOM reference
     }
        innerFunction();
    

    } 外部函数(1);

    【讨论】:

      猜你喜欢
      • 2021-01-19
      • 2016-04-08
      • 2018-10-30
      • 2018-12-24
      • 1970-01-01
      • 2011-10-20
      • 1970-01-01
      • 2022-01-25
      • 1970-01-01
      相关资源
      最近更新 更多