我一直在尝试为JavaScript中的动态创建的“a”标记的onclick事件分配一个函数。所有标签都在循环中创建,如下所示:
for ( var i = 0; i < 4; i++ )
{
var a = document.createElement( "a" );
a.onclick = function( ) { alert( i ) };
document.getElementById( "foo" ).appendChild( a );
}
所有四个链接的警报值始终为“4”。很明显。谷歌搜索时,我遇到了一个显示以下代码片段的帖子:
a.onclick = (function(p, d) {
return function(){ show_photo(p, d) }
})(path, description);
我设法根据我的需要调整它并获得警报(i)正常工作的事情,但如果有人能够准确解释上述代码的作用,我将不胜感激。
答案 0 :(得分:45)
将功能分配给点击处理程序时,会创建closure。
基本上,当您嵌套函数时会形成闭包,即使在父函数已经执行之后,内部函数也可以引用其外部封闭函数中存在的变量。
在执行click事件时,处理程序引用i
变量的最后一个值,因为该变量存储在闭包中。
正如您所注意到的,通过包装单击处理程序函数以接受i
变量作为参数,并返回另一个函数(基本上创建另一个闭包),它可以按预期工作:
for ( var i = 0; i < 4; i++ ) {
var a = document.createElement( "a" );
a.onclick = (function(j) { // a closure is created
return function () {
alert(j);
}
}(i));
document.getElementById( "foo" ).appendChild( a );
}
迭代时,实际创建4个函数,每个函数在创建时都存储对i
的引用(通过传递i
),此值存储在外部闭包和内部触发click事件时执行函数。
我使用以下代码片段来解释闭包(以及curry的一个非常基本的概念),我认为一个简单的例子可以更容易理解这个概念:
// a function that generates functions to add two numbers
function addGenerator (x) { // closure that stores the first number
return function (y){ // make the addition
return x + y;
};
}
var plusOne = addGenerator(1), // create two number adding functions
addFive = addGenerator(5);
alert(addFive(10)); // 15
alert(plusOne(10)); // 11
答案 1 :(得分:10)
如果没有详细介绍,这实际上会创建实例变量的副本,方法是将它们包装在一个立即执行的函数中,然后将其传递给将在单击该元素时执行的函数。
这样想:
function() { alert(i); } // Will expose the latest value of i
(function(I) { return function() { alert(I); }; })(i); // Will pass the current
// value of i and return
// a function that exposes
// i at that time
因此,在循环的每次迭代中,您实际上正在执行一个函数,该函数返回带有变量的当前值的函数。 / p>
其中,如果你想象你的循环中有4个锚点,你就会创建4个独立的函数,可以看作是......
function() { alert(0); };
function() { alert(1); };
function() { alert(2); };
function() { alert(3); };
我会考虑使用javascript调查范围和闭包,就好像你走这条路并且不明白究竟发生了什么,你可能会遇到意外行为导致的大量问题。
答案 2 :(得分:2)
当触发onclick事件时,将调用匿名函数,它引用循环中使用的同一变量i
,它保留最后一个值i
,即4。
问题的解决方案是使用函数返回函数:
a.onclick = (function(k) {return function() { alert(k); }; })(i);