For循環(huán)+setTimeout中那些趣事

今天面試再次遇到for+setTimeout問題。再次仔細品嘗了一下,也算獲取更多一點知識,接下來,我們把它完全搞清楚。

第一個例子

for(var i=0;i<10;i++){? setTimeout(console.log(i),1000);//0-10}
這個可能很多人一上來會說應該打印10個10,其實不是,是0-9.為什么呢,因為console.log()是立即執(zhí)行函數(shù)也就是IIFE,而console.log只是一個function 函數(shù)名。所以console.log()是同步任務跟for循環(huán)是同步執(zhí)行的,而setTimeout()是異步任務需要等到主線程的同步任務執(zhí)行完畢后才能執(zhí)行,所以結(jié)果就是0、1、2、3、4、5、6、7、8、9了。
第二個例子

for(var i=0;i<10;i++){? setTimeout(()=>{? ? ?console.log(i)? },1000);//10個10}
這個應該都熟悉,打印10個10,因為setTimeout是異步函數(shù),加上打印的是外面的變量,因為使用var 聲明變量i。相當于下面這樣,等隊列任務處理完,輪到打印的時候,i已經(jīng)是10啦。
var i;for(i=0;i<10;i++){? setTimeout(()=>{? ? ?console.log(i)? },1000);//10個10}
第三個例子

for (var i=1; i<=5; i++) {? ?(function(j) {? ? ? ?setTimeout( function timer() {? ? ? ? ? ?console.log( j );? ? ? ?}, j*1000 );? ?})(i);}
這個稍微不一樣,原因是有了閉包,很多同志還不清楚閉包到底是什么。一句話就是:在一個嵌套函數(shù)中,函數(shù)內(nèi)部可以引用外部的參數(shù)和變量,并且不被GC回收,也就是函數(shù)內(nèi)部被其它引用了。
第四個例子

for (let i=1; i<=5; i++) {? ?setTimeout( function timer() {? ? ? ?console.log( i );? ? }, i*1000 );}
這個沒有什么說的用了let,每次循環(huán)會有單獨的作用域。
春生萬物生

function timer(i) {? ?setTimeout( console.log( i ), i*1000 );}for (var i=1; i<=5;i++) {? ?timer(i);}
這個又是為什么呢,仔細一看,就和第一個一樣的,只是視野混淆了。也是IIFE。

總結(jié)
1、IIFE、閉包一類都是解決它最后打印的是它循環(huán)的最后一個值。

評論
圖片
表情
