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
這是一個常見的面試考題。分兩部分說明,關於順序可以參考我先前的文章:
這邊還還是簡短說明,總之 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