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、闭包一类都是解决它最后打印的是它循环的最后一个值。
评论