For循环+setTimeout中那些趣事

今天面试再次遇到for+setTimeout问题。再次仔细品尝了一下,也算获取更多一点知识,接下来,我们把它完全搞清楚。

第一个例子

for(var i=0;i<10;i++){setTimeout(console.log(i),1000);//0-10}
这个可能很多人一上来会说应该打印10个10,其实不是,是0-9.为什么呢,因为console.log()是立即执行函数也就是IIFE,而console.log只是一个function 函数名。所以console.log()是同步任务跟for循环是同步执行的,而setTimeout()是异步任务需要等到主线程的同步任务执行完毕后才能执行,所以结果就是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是异步函数,加上打印的是外面的变量,因为使用var 声明变量i。相当于下面这样,等队列任务处理完,轮到打印的时候,i已经是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);}
这个稍微不一样,原因是有了闭包,很多同志还不清楚闭包到底是什么。一句话就是:在一个嵌套函数中,函数内部可以引用外部的参数和变量,并且不被GC回收,也就是函数内部被其它引用了。
第四个例子

for (let i=1; i<=5; i++) {setTimeout( function timer() {console.log( i );}, i*1000 );}
这个没有什么说的用了let,每次循环会有单独的作用域。
春生万物生

function timer(i) {setTimeout( console.log( i ), i*1000 );}for (var i=1; i<=5;i++) {timer(i);}
这个又是为什么呢,仔细一看,就和第一个一样的,只是视野混淆了。也是IIFE。

总结
1、IIFE、闭包一类都是解决它最后打印的是它循环的最后一个值。

评论
