for循環(huán) + setTimeout 結合一些示例(前端面試題)
一、背景
最近在翻看以前的老書《node.js開發(fā)指南》,恰好碰到 for 循環(huán) + setTimeout 的經(jīng)典例子,于是重新梳理了思路并記錄下。
二、寫在前面,setTimeout 和 setInterval 的執(zhí)行機制
在日常編碼中,你會發(fā)現(xiàn),給 setTimeout 和 setInterval 設定延遲時間往往并不準,或者干脆 setTimeout(function(){xxx},0) 也不是立馬執(zhí)行(特別是有耗時代碼在前),這是因為 js 是單線程的,有一個事件隊列機制,setTimeout 和 setInterval 的回調會到了延遲時間塞入事件隊列中,排隊執(zhí)行。
setTimeout :延時 delay 毫秒之后,啥也不管,直接將回調函數(shù)加入事件隊列。
setInterval :延時 delay 毫秒之后,先看看事件隊列中是否存在還沒有執(zhí)行的回調函數(shù)( setInterval 的回調函數(shù)),如果存在,就不要再往事件隊列里加入回調函數(shù)了。
看下面示例:
for (var i = 0; i < 5; i++) {
setTimeout(function() {
console.log(i);
}, 1000);
}
結果:1 秒之后,同時輸出 5 個 5。
因為 for 循環(huán)會先執(zhí)行完(同步優(yōu)先于異步優(yōu)先于回調),這時五個 setTimeout 的回調全部塞入了事件隊列中,然后 1 秒后一起執(zhí)行了。
三、正文
接下來就是那道經(jīng)典的代碼:
for (var i = 0; i < 5; i++) {
setTimeout(function (){
console.log(i);
},1000);
}
結果:5 5 5 5 5
為什么不是 1 2 3 4 5,問題出在作用域上。
因為 setTimeout 的 console.log(i); 的i是 var 定義的,所以是函數(shù)級的作用域,不屬于 for 循環(huán)體,屬于 global。等到 for 循環(huán)結束,i 已經(jīng)等于 5 了,這個時候再執(zhí)行 setTimeout 的五個回調函數(shù)(參考上面對事件機制的闡述),里面的 console.log(i); 的 i 去向上找作用域,只能找到 global下 的 i,即 5。所以輸出都是 5。
解決辦法:人為給 console.log(i); 創(chuàng)造作用域,保存i的值。
解決辦法一
for (var i = 0; i < 5; i++) {
(function(i){ //立刻執(zhí)行函數(shù)
setTimeout(function (){
console.log(i);
},1000);
})(i);
}
這里用到立刻執(zhí)行函數(shù)。這樣 console.log(i); 中的i就保存在每一次循環(huán)生成的立刻執(zhí)行函數(shù)中的作用域里了。
解決辦法二
for (let i = 0; i < 5; i++) { //let 代替 var
setTimeout(function (){
console.log(i);
},1000);
}
let 為代碼塊的作用域,所以每一次 for 循環(huán),console.log(i); 都引用到 for 代碼塊作用域下的i,因為這樣被引用,所以 for 循環(huán)結束后,這些作用域在 setTimeout 未執(zhí)行前都不會被釋放。
四、補充
在寫示例代碼的過程中,發(fā)現(xiàn)一個語法點:
function a(i){
console.log(i);
}
for (var i = 0; i < 5; i++) {
setTimeout(a(i),1000);
}
報錯:
TypeError: "callback" argument must be a function at setTimeout (timers.js:421:11) ……
百度了下,原來 setTimeout 不支持傳帶參數(shù)的函數(shù),可以再用一個匿名函數(shù)包裝下它吧,見下面代碼:
function a(i){
console.log(i);
}
for (var i = 0; i < 5; i++) {
setTimeout(function(){ //用匿名函數(shù)包裝
a(i);
},1000);
}
總結
以上所述是小編給大家介紹的for循環(huán) + setTimeout 結合一些示例(前端面試題),希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對腳本之家網(wǎng)站的支持!
相關文章
JavaScript實現(xiàn)漢字轉換為拼音及縮寫的方法示例
這篇文章主要介紹了JavaScript實現(xiàn)漢字轉換為拼音及縮寫的方法,結合實例形式分析了javascript數(shù)組遍歷、轉換實現(xiàn)漢字轉拼音相關操作技巧,需要的朋友可以參考下2019-03-03
JS/HTML5游戲常用算法之碰撞檢測 包圍盒檢測算法詳解【圓形情況】
這篇文章主要介紹了JS/HTML5游戲常用算法之碰撞檢測 包圍盒檢測算法,結合實例形式詳細分析了圓形包盒情況下的碰撞檢測算法相關原理與實現(xiàn)技巧,需要的朋友可以參考下2018-12-12
JavaScript實現(xiàn)谷歌瀏覽器插件開發(fā)的方法詳解
對于瀏覽器插件相信大家都不陌生,誰的瀏覽器不裝幾個好用的插件呢,更是有油猴這個強大的神器。所以本文就來用JavaScript開發(fā)一個谷歌瀏覽器插件,感興趣的小伙伴可以了解一下2022-11-11
TypeScript之元組、數(shù)組及as?const的使用
TypeScript中的元組、數(shù)組和as?const關鍵字對于類型安全性和代碼可讀性非常重要,本文主要介紹了TypeScript之元組、數(shù)組及as?const的使用,感興趣的可以了解一下2023-10-10
javascript實現(xiàn)帶下拉子菜單的導航菜單效果
這篇文章主要介紹了javascript實現(xiàn)帶下拉子菜單的導航菜單效果的方法,涉及javascript操作頁面元素與樣式的相關技巧,需要的朋友可以參考下2015-05-05

