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); 
相關問題