【翻譯】JavaScript循環和做用域

個人翻譯小站: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()
}
相關文章
相關標籤/搜索