在開始之前先看個面試例子
為什么會是0 1 2 2,而不是 0 0 1 1
再來看個例子
輸出結果是4個undefined,為何不是1,2,3,4?
這是為什么呢,這是因為setTimeout是異步的,運行機制是指定的代碼,必須等到本次執行的所有同步代碼都執行完,才會執行。優先關系:異步任務要掛起,先執行同步任務,同步任務執行完畢才會響應異步任務。
這里解釋下異步執行過程,瀏覽器有個定時器(timer)模塊,定時器到了執行時間才會把異步任務放到異步隊列,for循環體執行的過程中並沒有把setTimeout放到異步隊列中,只是交給定時器模塊了。4個循環體執行速度非常快(不到1毫秒)。定時器(即使設置了0默認也是4毫秒)到了設置的時間才會把setTimeout語句放到異步隊列中。
看張圖:
先來說說第一個例子:for循環結束時候此時j = 2,瀏覽器定時器模塊中的setTimeout交給了任務隊列后輸出,所以就有了0=》1=》2=》2
再來說說第二個例子:也是同樣的道理,messages執行了四次,然后for循環結束,此時i=4,因為messages[4]沒有值為undefined,最大為3,所有是4個undefined
最后說說例二解決方法
方法一:
使用let,不要用var,因為let是有作用域的,所以setTimeout的i值指向的是每個循環體中的i值,每次循環的值都是不一樣的,打印出來的是最終輸出1,2,3,4
方法二(閉包):
這個就很好理解了,因為每個i的值都會傳入function中,setTimeout中的i作用域在這個閉包中,每次指向的是閉包中的i,所以打印出來的值1,2,3,4
總結:setTimeout是異步函數,異步任務要掛起,先執行同步任務,同步任務執行完畢才會響應異步任務