解除 for 迴圈時 var 和 let 定義變數的困惑

xiaoYk發表於2017-11-16

這個問題的產生以及應用場景就不多說了,基本每個人都會遇到,下面直接上程式碼。

var a = [];
for (var i = 0; i < 10; i++) {
  a[i] = function () {
    console.log(i); // i 指向全域性的 i,也就是陣列中函式所有的i都指向的是同一個變數i
  };
}
a[6](); // 10
複製程式碼

上面程式碼中,變數i是var命令宣告的,在全域性範圍內都有效,所以全域性只有一個變數i。每一次迴圈,變數i的值都會自增,而迴圈內被賦給陣列a的函式內部的console.log(i),裡面的i指向的就是全域性的i。也就是說,所有陣列a的成員裡面的i,指向的都是同一個i,導致執行時輸出的是迴圈結束之後i的值,也就是 10。

如果使用let,宣告的變數僅在塊級作用域內有效,最後輸出的是 6。

var a = [];
for (let i = 0; i < 10; i++) {
  a[i] = function () {
    console.log(i); //由於 let 建立的變數是塊級作用域的,所以在這個函式內每次都儲存一個新的 i
  };
}
a[6](); // 6
複製程式碼

這是因為let 建立的變數是塊級作用域的,所以每次迴圈都是一個新的 i,每次的值都是 i++ 的結果。因為每次迴圈的 i 都是一個獨立的變數(記憶體裡的唯一地址),因此閉包記錄的值都是唯一的,所以才能得到最終的結果

如果用 var 的話,變數 i 是一個全域性變數,雖然迴圈體內每次都建立了一個函式來列印 i,但是當時當刻僅僅是一個指向全域性變數 i 的指標,當迴圈結束之後無論你用哪一個下標去訪問迴圈建立的閉包函式,列印的變數 i 都是全域性的那一個,所以全部都是 10。

相關文章