2016-04-22 68 views
0

我有一段代碼,我試圖讓警報1,2,3。我遇到了正確使用閉包的問題,​​所以我無法弄清楚這一點。問題關閉工作

原始代碼:

function buildList(list) { 
    var result = []; 
    for (var i = 0; i < list.length; i++) { 
     var item = 'item' + list[i]; 
     result.push(function() {alert(item + ' ' + list[i])}); 
    } 
    return result; 
} 

function testList() { 
    var fnlist = buildList([1,2,3]); 
    // using j only to help prevent confusion - could use i 
    for (var j = 0; j < fnlist.length; j++) { 
     fnlist[j](); 
    } 
} 

testList(); 

我試圖做這樣的事情來buildList()得到它才能正常工作:

function buildList(list) { 
    var result = []; 
    for (var i = 0; i < list.length; i++) { 
     var item = 'item' + list[i]; 
     result[i] = function(x) { 
      result.push(function() {alert(item + ' ' + list[x])}); 
     }(i); 
    } 
    return result; 
} 

我知道我與工作決策失誤關閉,我只是不確定問題是什麼。

回答

0

你的第二個嘗試是接近的解決方案,但仍然因爲你內心最函數是從頂層功能捕捉變量item不起作用:item只是總是引用相同的情況下,這是主叫buildList()時創建。

var JavaScript中的範圍始終與當前函數調用綁定,而不是代碼塊,因此它不受像for這樣的控制語句的約束。

因此,警報可能顯示'item' + (list.length-1)在調用buildList()時的值。

既然你是路過i你關閉,你應該是函數內聲明var item,如:

function buildList(list) { 
    var result = []; 
    for (var i = 0; i < list.length; i++) { 
     result[i] = function(x) { 
      // x and item are both local variables of anonymous function declared just above 
      var item = 'item' + list[x]; // or maybe you meant 'item' + x? 
      return function() {alert(item + ' ' + list[x])}; 
     }(i); 
    } 
    return result; 

}

注意,關閉將仍然捕捉到list的引用,以便將顯示它在調用buildList()返回的數組中的函數時包含的值。另外本地變量item是完全可選的,您可以撥打alert('item' + x /*or is it list[x]?*/ + ' ' + list[x])

0

How do JavaScript closures work?

注意,當您運行的例子中,「項目2未定義」被警告3次 !這是因爲就像前面的例子一樣,buildList的局部變量只有一個 閉包。當在行fnlistj上調用匿名函數 ;他們都使用相同的 單閉包,並且他們使用當前值爲i和 內的項目,其中一個閉包(其中i的值爲3,因爲循環已完成 ,且項目的值爲'item2')。請注意,我們從 0開始索引,因此項目的值爲item2。與I ++將增加我的 值3

你需要做一個封閉在每次循環迭代,如果你要存儲的i的匹配值:

function buildList(list) { 
    var result = [], item, closure; 
    for (var i = 0; i < list.length; i++) { 
    item = 'item' + list[i]; 

    // call this function with the string you wish to store 
    // the inner function will keep a reference to the 'msg' parameter even after the parent function returns 
    closure = (function(msg) { 
     return function() { 
      alert(msg); 
     }; 
     }(item + ' ' + list[i])); 
    result.push(closure); 
    } 
    return result; 
} 

function testList() { 
    var fnlist = buildList([1, 2, 3]); 
    // using j only to help prevent confusion - could use i 
    for (var j = 0; j < fnlist.length; j++) { 
    fnlist[j](); 
    } 
} 

testList(); 

同樣的問題問herehere。相同的答案here,here,here,here並且可能在十多個地方。