明月笑刀無情
2018-08-02 21:35:36
for (var i = 0; i < 5; i++) {
setTimeout(function() {
console.log(new Date, i);
}, 1000);
}console.log(new Date, i);能想到答案是5,5,5,5,5。感覺應該是因為異步代碼。但根據作者的話“ 只要你對 JS 中同步和異步代碼的區別、變量作用域、閉包等概念有正確的理解,就知道正確答案”。不知道這里怎么和閉包有關系。還有個就是輸出的結果為什么最后4個5是同時輸出的。2017-03-18T00:43:45.873Z 52017-03-18T00:43:46.866Z 52017-03-18T00:43:46.868Z 52017-03-18T00:43:46.868Z 52017-03-18T00:43:46.868Z 52017-03-18T00:43:46.868Z 5
2 回答

蝴蝶刀刀
TA貢獻1801條經驗 獲得超8個贊
閉包的產生就是局部作用域中有對外部作用域變量的引用,原代碼指向的是一個全局變量所以毫無意義
for (let i = 0; i < 5; i++) { setTimeout(function() { console.log(new Date, i); }, 1000); }console.log(new Date, i);
這樣就很好理解了,let聲明的變量具有塊級作用域,只有在代碼塊中能使用,代碼塊中掛起的異步函數能訪問到i(塊級作用域中的i)
異步函數中有對外部變量i的引用從而產生閉包
而外部使用變量會因為沒有聲明而報錯
一開始的代碼輸出5個5是因為執行異步代碼 setTimeout(function() { console.log(new Date, i); }, 100);
中的console.log(new Date, i);
時for循環已經完畢了,i已經是5了,注意setTimeout(...)
是同步的,其中的代碼塊是異步的
或者這樣
for (var i = 0; i < 5; i++) { (function(i){ setTimeout(function() { console.log(new Date, i); }, 1000); })(i); }console.log(new Date, i);
這里相當于保存了i的快照版本作為參數傳入
至于為什么是同步輸出的(其實是依次輸出的),for循環執行setTimeout是同步的,又沒阻塞代碼存在每次循環的時間間隔小到可以忽略不計,執行異步代碼也沒有其他異步代碼與阻塞代碼的干擾,所以執行的時候感覺是一瞬間一起出現的

互換的青春
TA貢獻1797條經驗 獲得超6個贊
setTimeout是延時執行,但是他其實是不準確的。后面的毫秒數代表著他在多少毫秒后會進入執行隊列里面。如果你前面有一個占用了非常多時間的運算。setTimeout就會延時特別久。他只在當前隊列執行完之后,才嘗試執行。
for (var i = 0; i < 5; i++) { //延遲執行 setTimeout(function() { console.log(new Date, i); }, 1000); } console.log(new Date, i); alert("我們用alert掛起一下程序,你等待兩三秒再確定");//執行到這里,這個隊列才算是執行完了。然后才會嘗試執行你的settimeout延時的程序,看看是不是可以調用了。不信你看看時間
添加回答
舉報
0/150
提交
取消