这些JS代码片段如何工作?

时间:2012-10-19 14:21:11

标签: javascript

我正在阅读有关闭包的内容,我很难理解这两个代码段之间的区别:

var myElements = [ /* DOM Collection */ ];

for (var i = 0; i < 100; ++i) {
    myElements[i].onclick = function() {
        alert( 'You clicked on: ' + i );
    };
}

以上代码只应为每个onclick

显示i为99
function getHandler(n) {
    return function() {
        alert( 'You clicked on: ' + n );
    };
}

for (var i = 0; i < 100; ++i) {
    myElements[i].onclick = getHandler(i);
}

以上代码为每个元素点击事件显示正确的'i'值!

我无法理解为什么第一个没有显示i的正确值。如果没有,为什么第二个显示正确的值?

他们来自this link

7 个答案:

答案 0 :(得分:4)

  

我无法理解为什么第一个没有显示i的正确值。

这是因为闭包不会捕获i,而是捕获实际的局部变量i。当您继续更改i的值时,闭包会看到这些更改,因为它仍在使用相同的变量。

  

如果没有,为什么第二个显示正确的值?

因为在第二个中,闭包是捕获局部变量n,后来永远不会改变。 (稍后对getHandler的调用有一个全新的局部变量n;这不仅对闭包很重要,而且对支持递归也很重要。否则对函数的不同调用可能会意外地混淆彼此的变量!)

答案 1 :(得分:1)

当点击发生时,它们都显示值。

在第一个中,只有一个i,点击发生时为99

在第二个问题中,每次调用n时都会有一个新getHandler

答案 2 :(得分:0)

第一个显示每个99,因为在调用函数时,i的值为99.

第二个显示正确的值,因为您关闭了i(通过参数n)。这意味着,i将继续更改,n会在调用函数时保留该值。

答案 3 :(得分:0)

在第一个示例中,onclick函数在循环中创建,引用i,但在单击发生之前不会执行。触发单击时,函数执行,并读取i,现在设置为99。

在第二个示例中,getHandler(i)立即执行,返回参考n的函数。 (这就是为什么返回的函数被称为闭包:它已经“传递”的值“关闭”)。在这个新的函数范围中,n等于传入的值 - 您要查找的值。

答案 4 :(得分:0)

onclick函数注定要在以后解雇。

在第一种情况下,i的值在事件被触发之前丢失,

但在第二种情况下,i的值被复制&amp;保存以供日后使用。

答案 5 :(得分:0)

第二个例子起作用的原因和第一个例子没有与范围有关。在第一个示例中,变量i存储在全局范围内,并在单击按钮时读取。在您完成循环后,i为99.如果您仍然可以在循环中单击按钮1,那么您将获得i的当前值。 (顺便说一句,这是不可能的。)

在第二个示例中,i的副本存储在函数getHandler中,当您在循环中更改i时,该副本不会更改。 getHandler是您返回的(未命名)函数的范围,因此它是它所读取的变量。

答案 6 :(得分:0)

“i”变量绑定到范围,您可以创建一个新范围,其中“i”具有正确值时评估的函数

您可以实现此行为:

var myElements = [{}, {}];

for (var i = 0; i < 2; ++i) {
    myElements[i].onclick =
        function(i) {
            return function() {
                alert( 'You clicked on: ' + i );
            }
        }(i); // <- This behavior is the important one
}

问候