5 回答

TA貢獻1995條經驗 獲得超2個贊
好吧,問題是i每個匿名函數中的變量都綁定到函數外部的同一個變量。
經典解決方案:閉包
你想要做的是將每個函數中的變量綁定到函數之外的一個單獨的,不變的值:
var funcs = [];
function createfunc(i) {
return function() { console.log("My value: " + i); };
}
for (var i = 0; i < 3; i++) {
funcs[i] = createfunc(i);
}
for (var j = 0; j < 3; j++) {
funcs[j](); // and now let's run each one to see
}
由于JavaScript中沒有塊作用域 - 只有函數作用域 - 通過將函數創建包裝在新函數中,可以確?!癷”的值保持不變。
2015解決方案:forEach
隨著Array.prototype.forEach函數的相對廣泛的可用性(在2015年),值得注意的是,在涉及主要在一組值上進行迭代的那些情況下,.forEach()提供了一種干凈,自然的方式來為每次迭代獲得一個獨特的閉包。也就是說,假設您有某種包含值的數組(DOM引用,對象等等),并且設置了特定于每個元素的回調問題,您可以這樣做:
var someArray = [ /* whatever */ ];
// ...
someArray.forEach(function(arrayElement) {
// ... code code code for this one element
someAsynchronousFunction(arrayElement, function() {
arrayElement.doSomething();
});
});
這個想法是每次調用與.forEach循環一起使用的回調函數都是它自己的閉包。傳遞給該處理程序的參數是特定于該迭代的特定步驟的數組元素。如果它在異步回調中使用,它將不會與在迭代的其他步驟中建立的任何其他回調沖突。
如果你碰巧在jQuery中工作,該$.each()函數會為你提供類似的功能。
ES6解決方案: let
ECMAScript 6(ES6)引入了新的let和const關鍵字,其范圍與var基于變量的不同。例如,在具有let基于索引的循環中,循環中的每次迭代都將具有一個新值,i其中每個值都在循環中作用域,因此您的代碼將按預期工作。有很多資源,但我建議將2ality的區塊范圍發布作為一個很好的信息來源。
for (let i = 0; i < 3; i++) {
funcs[i] = function() {
console.log("My value: " + i);
};
}
但要注意,IE9-IE11和Edge在Edge 14支持之前let卻出現了上述錯誤(它們i每次都沒有創建新的,所以上面的所有函數都會像我們使用的那樣記錄3 var)。Edge 14最終做對了。

TA貢獻1804條經驗 獲得超8個贊
嘗試:
var funcs = [];for (var i = 0; i < 3; i++) { funcs[i] = (function(index) { return function() { console.log("My value: " + index); }; }(i));}for (var j = 0; j < 3; j++) { funcs[j]();}

TA貢獻1865條經驗 獲得超7個贊
使用立即調用的函數表達式,這是封裝索引變量的最簡單,最易讀的方法:
for (var i = 0; i < 3; i++) { (function(index) { console.log('iterator: ' + index); //now you can also loop an ajax call here //without losing track of the iterator value: $.ajax({}); })(i);}
這會將迭代器發送i
到我們定義為的匿名函數中index
。這將創建一個閉包,i
保存變量以供以后在IIFE中的任何異步功能中使用。

TA貢獻1824條經驗 獲得超5個贊
另一種說法是,i
函數中的函數在執行函數時受到約束,而不是創建函數的時間。
創建閉包時,i
是對外部作用域中定義的變量的引用,而不是創建閉包時的副本。它將在執行時進行評估。
大多數其他答案提供了通過創建另一個不會為您更改值的變量來解決的方法。
我想我會添加一個清晰的解釋。對于一個解決方案,就個人而言,我會選擇Harto,因為從這里的答案來看,這是最不言自明的方式。發布的任何代碼都可以使用,但我選擇封閉工廠而不必寫一堆注釋來解釋為什么我要聲明一個新變量(Freddy和1800's)或者有奇怪的嵌入式閉包語法(apphacker)。
添加回答
舉報