2013-10-18 42 views
0

我想在for循環中爲li添加事件。JavaScript:在循環中添加事件 - 混淆問題

我知道總是出錯:關閉可以訪問的i是最後一個值i。需要將i鎖定在關閉位置。

要解決這個問題,請立即調用函數表達式。

我不明白的是爲什麼這不起作用!

for (var i = 0; i < 10; i++){ 
    var li = document.createElement('li'); 
    ul.appendChild(li); 
    li.onclick = (function(i2){ 
     return slideTo(i2); // slideTo is a global function 
    }(i)); 

但我知道這將工作:

li.onclick = (function(i2){ 
    return function(){ 
     slideTo(i2);  // slideTo is a global function 
    } 
}(i)); 

爲什麼我需要把slideTo(i)成一個匿名函數???

這兩個表達式有什麼區別?

非常感謝!

回答

0

在第一種情況下,你只是在指定的slideTo(i2)值到onclick

li.onclick = (function(i2){ 
    // Here, "i2" is **immediately** used to invoke 
    // slideTo(i2). It is invoked right here, in 
    // every loop iteration. 
    return slideTo(i2); 
}(i)); 

以上將在每次循環進行評估,所以它等同於:

li.onclick = slideTo(i); 

在合同中,在第二個示例中,創建一個適當的關閉,從而將函數(不是,類似於第一種情況)分配給li.onclick監聽器:

li.onclick = (function(i2){ 
    // Here, "i2" is in a scope, but it's **not immediately** used. 
    // Instead, you are returning function which will be assigned 
    // to "li.onclick" but with THIS scope (i.e. scope with 
    // "i2" value). 
    // 
    // New scope is created in every loop iteration, but the following 
    // function **is not called** in a loop. 
    return function() { 
     // Later, when <li> is clicked, slideTo(i2) will be called. 
     slideTo(i2); 
    } 
}(i)); 
+0

感謝您的幫助!所以如果我沒有錯,第一個場景會立即調用slideTo(is2)並返回一個值。而第二個函數將返回一個函數:function(){slideTo(i2)}作爲一個整體,現在不會被調用。我對嗎? – flyaway

+0

@flyaway - 是的。在第二個例子中,評估整個表達式'(function(i2){return function(){slideTo(i2);}}(i))'。外部函數被立即調用,所以你得到的是'li.onclick = function(){slideTo(i2)}'但具有不同的作用域(感謝外部函數。 – kamituel

0

的第二形式是必需的以創建變量結合(即,i2) - 第一種形式是立即評價(它不返回一個功能對象它執行後工作),因此不是「回調」。

請記住,只有新的功能範圍創建新的變量。如果沒有雙閉合,你會參考相同的i變量。另一種方法是使用Function.bind(它本身可以用閉包來模擬)。