JS函數的執行時機

1. 爲什麼如下代碼會打印 6 個 6
let i = 0
for(i = 0; i < 6; i++){
  setTimeout(()=>{
    console.log(i)
  },0)
}

當setTimeout()的毫秒數設置爲0的時候,是要先執行完函數調用棧中的代碼,然後立即調用定時器。

因爲定時器都被放在了一個隊列中,等待上下文的可執行代碼運行完畢後,纔開始運行定時器,也就是定時器纔剛開始計時。代碼中聲明一個let全局變量i,然後在for循環中改變i,所以在定時器的方法執行的時候,變量i已經變成了6,所以輸出的全部是6。

2. 讓上面代碼打印 0、1、2、3、4、5 的方法
for(let i = 0; i < 6; i++){
  setTimeout(() => {
    console.log(i)
  }, 0)
}

在這裏插入圖片描述

利用ES6 let命令聲明變量塊級作用域的概念,和前面for循環使用全局變量i不同,當前的i只在本輪循環有效, 所以每一次循環的i其實都是一個新的變量,所以5個setTimeout回調函數雖然都引用了變量i,但實際上這5個i是獨立的,僅在自己的塊級作用域內有效

3. 除了使用 for let 配合,還有什麼其他方法可以打印出 0、1、2、3、4、5
let i
for (i = 0; i < 6; i++) {
  // j = i
  !(function(j) { 
    setTimeout(() => {
      console.log(j)
    }, 0);
  })(i);
}

在這裏插入圖片描述
這裏通過立即執行函數創造了n個不同的函數作用域,給setTimeout傳入n個不同的參數,所以就可以打印出0、1、2、3、4、5 此外,我們還可以

let output = function(i) {
  setTimeout(function() {
    console.log(i);
  }, 0);
};
let i
for (i = 0; i < 6; i++) {
  output.call(undefined, i); // 這裏傳過去的 i 值被複制,而不是引用
}

在這裏插入圖片描述
原理和上面相似,也是創造了n個不同的函數作用域,給setTimeout傳入了n個不同的參數

此外我們還可以利用setTimeout第三個參數

let i
for (i = 0; i < 6; i++) {
  setTimeout(function(i) {
    console.log(i);
  }, 0, i);
}

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章