2

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

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

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

上面的代码应该只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。如果不是,为什么第二个显示正确的值?

它们取自此链接

4

7 回答 7

4

我不明白为什么第一个不显示正确的值i

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

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

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

于 2012-10-19T14:24:21.600 回答
1

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

在第一个中,只有一个i,它是99点击发生的时候。

在第二个中,n每次getHandler调用都有一个新的。

于 2012-10-19T14:23:51.777 回答
0

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

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

于 2012-10-19T14:23:48.590 回答
0

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

在第二个示例中,getHandler(i)立即执行,返回一个引用 的函数n。(这就是返回函数被称为闭包的原因:它已经“关闭”了传入的值)。在这个新的函数作用域中,n等于传入的值——你正在寻找的值。

于 2012-10-19T14:25:18.517 回答
0

onclick函数注定会在以后被触发。

在第一种情况下, i 的值会丢失,直到事件被触发,

但在第二种情况下, i 的值被复制并保存以备后用。

于 2012-10-19T14:25:47.247 回答
0

第二个示例有效而第一个示例无效的原因与范围有关。在第一个示例中,变量i存储在全局范围内,并在您单击按钮时读取。当你完成循环时,i是 99。如果你在循环中能够点击按钮 1,你会得到当前的值i。(顺便说一句,这是不可能的)。

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

于 2012-10-19T14:26:25.803 回答
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
}

问候

于 2012-10-19T14:46:39.950 回答