我正在阅读有关闭包的内容,我很难理解这两个代码段之间的区别:
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
答案 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
}
问候