迴圈中的閉包 for中套用setTimeout
阿新 • • 發佈:2019-01-02
迴圈中的閉包
一個常見的錯誤出現在迴圈中使用閉包,假設我們需要在每次迴圈中呼叫迴圈序號
for(var i = 0; i < 10; i++) {
setTimeout(function() {
console.log(i);
}, 1000);
}
上面的程式碼不會輸出數字 0
到 9
,而是會輸出數字 10
十次。
當 console.log
被呼叫的時候,匿名函式保持對外部變數 i
的引用,此時 for
迴圈已經結束, i
的值被修改成了 10
為了得到想要的結果,需要在每次迴圈中建立變數 i
的拷貝。
避免引用錯誤
為了正確的獲得迴圈序號,最好使用 匿名包裝器(譯者注:其實就是我們通常說的自執行匿名函式)。
for(var i = 0; i < 10; i++) {
(function(e) {
setTimeout(function() {
console.log(e);
}, 1000);
})(i);
}
外部的匿名函式會立即執行,並把 i
作為它的引數,此時函式內 e
變數就擁有了 i
當傳遞給 setTimeout
的匿名函式執行時,它就擁有了對 e
的引用,而這個值是不會被迴圈改變的。
有另一個方法完成同樣的工作,那就是從匿名包裝器中返回一個函式。這和上面的程式碼效果一樣。
for(var i = 0; i < 10; i++) {
setTimeout((function(e) {
return function() {
console.log(e);
}
})(i), 1000)
}