JavaScript 循環與作用域
JavaScript 有一個特性可能會給開發者帶來一些困擾,那就是與循環和作用域相關的問題。
讓我們來看一個例子:
1 | const operations = [] |
這段代碼遍歷了 5 次,每次將一個函數添加到名為 operations
的數組中。這個函數會將循環索引變量 i
輸出到控制台。
之後這些函數會被執行。
預期結果應該是:
1 | 0 |
但實際上卻是這樣的:
1 | 5 |
為什麼會這樣呢?這是因為使用了 var
。
由於 var
声明是提升的,上面的代碼等價於:
1 | var i; |
因此,在 for-of 循環中,i
仍然是可見的,它的值等於 5,函數中對 i
的任何引用都將使用這個值。
那麼,我們應該如何使事情按我們的意願運行呢?
最簡單的解決方案是使用 let
声明。在 ES6 中引入的 let
声明可以很好地避免 var
声明的一些怪異問題。
只需將循環變量中的 var
改為 let
就能正常工作:
1 | const operations = [] |
下面是輸出結果:
1 | 0 |
為什麼會這樣呢?這是因為在每次循環迭代中,i
都會被創建為一個新的變量,並且添加到 operations
數組的每個函數都有自己的 i
副本。
請記住,你不能在這種情況下使用 const
,因為在第二次迭代中,for
嘗試將新值賦給它會引發錯誤。
解決這個問題的另一種方式在 ES6 前的代碼中很常見,被稱為立即執行函數表達式(IIFE)。
在這種情況下,你可以將整個函數包裹起來,並將 i
綁定到它上面。由於以這種方式創建的函數立即被執行,你從中返回了一個新的函數,所以稍後可以執行它:
1 | const operations = [] |