個人翻譯小站:https://www.zcfy.cc/article/javascript-loops-and-scopejavascript
翻譯原文連接: https://flaviocopes.com/javascript-loops-and-scope/JavaScript有一個特色,也許會讓開發者頭痛, 是與循環和做用域相關的.java
舉個例子:數組
const operations = [] for (var i = 0; i < 5; i++) { operations.push(() => { console.log(i) }) } for (const operation of operations) { operation() }
它基本是循環了5次,將一個函數添加到operations數組裏面。這個函數可打印出循環變量索引值i
.函數
運行這些函數後oop
指望的結果應該是:spa
0 1 2 3 4
但實際發生的是這樣的:翻譯
5 5 5 5 5
爲何會有這種狀況? 由於使用的是var
.code
因爲提高了var
變量, 上面的代碼等同於blog
var i; const operations = [] for (i = 0; i < 5; i++) { operations.push(() => { console.log(i) }) } for (const operation of operations) { operation() }
所以,在for-of循環中, i
依然是可見的, 它等於5,而且每次在函數中涉及到i
,都將使用這個值。索引
那麼咱們應該如何作讓其變成咱們想的這樣呢?
最簡單的方案是用 let
聲明. 在ES2015中介紹到, 它們有很大的幫助,能避免關於使用var
聲明的一些奇怪問題。
簡單的在循環變量時將var
變成 let
,可以很好的運行:
const operations = [] for (let i = 0; i < 5; i++) { operations.push(() => { console.log(i) }) } for (const operation of operations) { operation() }
這是輸出結果:
0 1 2 3 4
這是怎麼實現的呢?這是由於每次循環重複的時候,都將從新創造i
,同時每一個函數添加operations
數組時,能獲取它自己的i
。
記住你不能使用 const
在這種狀況下, 由於這會致使for
在第二次循環時, 嘗試賦新值報錯。
另一個很是廣泛的解決這個問題是使用pre-ES6代碼, 同時它被稱做即時調用函數表達式 (IIFE).
在這種狀況下,你能夠包裝整個函數,並將i
綁定在它上面。自這種方式,你正在創造一個能當即執行的函數,你從其返回的一個新的函數。所以咱們能夠稍後執行它。
const operations = [] for (var i = 0; i < 5; i++) { operations.push(((j) => { return () => console.log(j) })(i)) } for (const operation of operations) { operation() }