21

我一直在尝试为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); 

我设法调整它为我的需求,并得到了警报(我)的东西才能正常工作,但我会很感激,如果有人可以解释不清楚上面的代码做了什么。

+0

嗨,你能告诉我,为什么它警报“4”?它不应该是“2”吗?谢谢。 – Tarik 2009-10-12 06:39:11

+0

for(var i = 0; i <3; i ++)在结尾处留下i == 4 – 2009-10-12 07:49:56

+1

不,它离开我为3 – 2009-10-12 08:26:50

回答

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),该值存储在外部闭包中,并且在点击事件触发时执行内部函数。

我用下面的代码片段来解释关闭(和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 
+3

泰勒,我为你高兴,我会让你完成,但这篇文章是所有时间中最好的。 – Tarik 2009-10-12 06:21:34

+0

难怪你有42k点:) – 2009-10-12 07:49:13

+4

有一天,人们会忘记Kanye West,就像我一样,所有提到他的模因会变得粗鲁和有点奇怪。 – RandomInsano 2010-06-23 15:01:35

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 

所以每次循环过程中,你实际上是执行返回一个功能与变量的当前值的函数。

其中,如果您想象一下你在你的循环,你正在创建一个可以看作4个独立的功能4个锚..

function() { alert(0); }; 
function() { alert(1); }; 
function() { alert(2); }; 
function() { alert(3); }; 

我会考虑寻找到的范围和封闭的JavaScript,如果你沿着这条道路走下去,不明白到底发生了什么事情,你可能会遇到来自意外行为的巨大问题。

+0

感谢您的解释。这是一个很好的黑客 - 或者是它在JavaScript中完成的方式? – Amarghosh 2009-10-12 06:21:01

2

当触发onclick事件,匿名函数被调用,它指的是在循环中使用的相同的变量i和其持有的i的最后一个值,即4

该溶液至你的问题是使用函数返回一个功能:当您分配功能到单击处理

a.onclick = (function(k) {return function() { alert(k); }; })(i); 
相关问题