JavaScript闭包和范围链

时间:2014-04-21 13:42:26

标签: javascript

有人可以解释为什么document.write部分总是输出10?

 function creatFunctions() {
     var result = new Array();
     for (var i = 0; i < 10; i++) {
         result[i] = function () {
             return i;
         }
     }
     return result;
 }
 var funcs = creatFunctions();

 for (var i = 0; i < funcs.length; i++) {
     document.write(funcs[i]() + "<br />");
 }

我认为这个问题的答案比重复的问题更彻底,因此值得保留这篇文章。

5 个答案:

答案 0 :(得分:9)

不确定

for循环中,您引用i。您期望发生的是每个闭包在创建函数时获取i的快照,因此在第一个函数中它将返回0,然后是1,等等。

真正发生的是每个闭包都会获得对外部变量i的引用,该变量会在i循环中更新for时不断更新。

所以,第一次通过循环,你得到一个返回i的函数,此时它是0.下次你得到两个返回i的函数,现在是1等等。

在循环结束时,i==10,每个函数返回i,因此它们都返回10.

更新以回答评论中的问题:

由于您在两个不同的上下文中使用i,因此有点混乱。我会对您的代码进行一些微小的更改,以帮助说明正在进行的操作:

function creatFunctions() {
    var result = new Array();
    for (var i = 0; i < 10; i++) {
        result[i] = function () {
            return i;
        }
    }
    return result;
}
var funcs = creatFunctions();

// NOTE: I changed this `i` to `unrelated_variable`
for (var unrelated_variable = 0; unrelated_variable < funcs.length; unrelated_variable++) {
    document.write(funcs[unrelated_variable]() + "<br />");
}

...您在creatFunctions()函数中创建的函数都返回i。具体来说,它们返回您在for循环中创建的i

我已将其重命名为unrelated_variable的另一个变量对关闭时返回的值没有影响。

result[i] = function () {
    return i;
}

...与result[2] = 2不同。这意味着result[2] = the_current_value_of_i

答案 1 :(得分:4)

因为您将i引用为变量,当函数执行时,变量的值为10。相反,您可以通过包装函数来创建i的副本:

(function (i) {
    result[i] = function () {
        return i;
    }
}(i));

答案 2 :(得分:3)

你在内部函数中返回的i是在i内声明的for(var i=0...) - 它对于所有的i是相同的result中的函数 当你调用函数时,它的值是10(循环结束后)

要完成你想要的,你应该在匿名函数范围内声明另一个变量

答案 3 :(得分:1)

因为对“i”的引用是在您定义的闭包中加框(附上)。

result[i] = function () {
             return i;
 }

它只是引用了“i”var,它随着每次迭代而不断变化。

答案 4 :(得分:0)

<强>更新

这与定义变量上下文的this关键字函数作用域有关。 因此,在JavaScript中,没有块范围(forif elsewhile,......)。

考虑到这一点,如果将var funcs分配给函数 definition 调用,函数体(this)将绑定到全局范围该函数内的var i将到达for循环的末尾并保留在内存中。在这种情况下,i为10。

不幸的是,由于函数范围将每个变量放在顶部,var i也是全局变量

虽然我一开始就完全错了,但我会立即纠正并冒昧地在demo中创建脚本的输出。