欣迪
codes on tilt shift lens
console.log("start")

for(var i = 0; i < 10; i++) {
  setTimeOut(() => { console.log(i) }, 1000)
}

console.log("end")

[題目] 請指出 console.log 的結果

這邊也不賣關子,答案不是 “start”, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, “end”

而是 “start”, “end”, 10 個 10

這是一個常見的面試考題。分兩部分說明,關於順序可以參考我先前的文章:

Macrotask 和 microtask

這邊還還是簡短說明,總之 js 在執行 event 的時候,會先處理能同步處理的任務,所以像是 setTimeOut, Promise 這種非同步處理的功能都會被拉出來,移到最後處理。

上面可以解釋為什麼 “start”, “end” 會先出來。

但是為什麼出現的數值是 10 個 10 呢?

首先 var 定義的 i 是一個全域變數。 for loop 是一個同步處理的函數。 每一次的 loop 裡面,都會重新定義一次 i 。

所以 setTimeOut 被移出後,所 console.log 的 i 是一個已經跑完 loop 的全域變數。

但是我當時在想這題時有個新疑惑,為什麼會是 10 而不是 9 呢 ? 照理說 i 跑到 9 就結束了啊,怎麼會是 10 呢? 看看下面的延伸題吧。

衍伸題

for(var i = 0; i < 10; i++) {
  console.log(i)
}
console.log(i)

這邊排除了所有非同步處理的因素。看看最後的結果是什麼!

直接說答案吧!

1, 2, 3, 4, 5, 6, 7, 8, 9, 10

仔細想想簡單到炸。 把 for loop 這件事拆開。

var i = 0 我們定義了一個全域的變數 i 。

i < 10 第二個是繼續執行 loop 的條件。

i++ 每一次 loop 之後的動作。

所以 i 要小於 10 才會繼續進入下一個 loop 定義的 event , 也就是中括號裡面的動作。

所以當 i 是 1 ~ 9 的時候,他會執行裡面的動作,並在結束時做一次 i ++。

所以當 i === 9 進入 loop 時,會再完成最後次 i++。 這時候的 i 已經變成 10。

真的很容易在簡單的環節卡住呢!

這篇解釋的很棒: [JS基礎] 從for loop搭配setTimeout理解JS runtime, scope, var & let

訂閱 IT-Monk

訂閱最新文章的發布消息! 😚😚😚
Loading

作者介紹 - 欣迪

欣迪

從設計到寫程式,發現自己有追求前端技巧的自虐傾向。不斷的踩坑,再從坑裡爬出來,慢慢對攀岩有點心得。 目前在多間公司擔任網站設計顧問。 同時也是網站架設公司負責人。