【圖解】幫你理解做用域與setTimeout

可能仍是不少同窗沒有理解下面的三段代碼,今天從原理分析一下git

var

for (var i = 0; i < 10; i++) {
    setTimeout(function() { console.log(i); }, 100 * i);
}
// 10 10 10 10 10 10 10 10 10 10

知識點:

  1. js只有全局做用域和函數做用域
  2. var存在變量提高
  3. 函數調用會造成一條做用域鏈,參數會沿着這個鏈條查找

圖解步驟

初始狀態,注意scope是指向定義函數的地方
github

執行for循環以後,i變成了10閉包

開始執行setTimeout回調,由於AO活動對象上沒有i,因此會從做用域鏈上查找,此時window上的i已是10函數

當即執行

for (var i = 0; i < 10; i++) {
    // capture the current state of 'i'
    // by invoking a function with its current value
    (function(i) {
        setTimeout(function() { console.log(i); }, 100 * i);
    })(i);
}
// 0 1 2 3 4 5 6 7 8 9

知識點

  1. 閉包能夠獲取外層函數做用域的變量

圖解步驟

初始狀態,注意scope是指向定義函數的地方spa

執行當即執行函數code

當即執行函數執行完畢,出棧,注意此時AO活動對象並不會被銷燬,而是暫存起來等待被調用對象

執行下一個循環, i = 1blog

當即執行函數執行完畢,出棧,注意此時AO活動對象並不會被銷燬,而是暫存起來等待被調用
資源

重複以上步驟,直到i=10,中止循環作用域

接下來就是執行setTimeout回調

由於setTimeout回調裏沒有i,因此從做用域鏈上查找,因此輸出0

接下來依次執行i = 1,2,3...時的setTimeout回調,同上

let

for (let i = 0; i < 10; i++) {
    setTimeout(function() { console.log(i); }, 100 * i);
}
// 0 1 2 3 4 5 6 7 8 9

知識點

  1. let會造成塊級做用域
  2. 每次迭代都會建立這樣一個新做用域

圖解步驟

初始狀態

下一個循環

繼續循環,直到10

接下來執行setTimeout回調

1~9同理

更多資源

https://github.com/abc-club/f...

相關文章
相關標籤/搜索