Heim > Fragen und Antworten > Hauptteil
24.看下面代码,给出输出结果。
javascript
for(var i=1;i<=3;i++){ setTimeout(function(){ console.log(i); },0); };
答案:4 4 4。
原因:Javascript事件处理器在线程空闲之前不会运行。那么问题来了,如何让上述代码输出1 2 3? //原因这句话是什么意思呀?
javascript
for(var i=1;i<=3;i++){ setTimeout((function(a){ //改成立即执行函数 console.log(a); })(i),0); };
7 1 //输出
8 2
9 3
巴扎黑2017-04-10 15:08:54
闭包的事情我就不多做解释了,其它人说的很多了,关于 "Javascript事件处理器在线程空闲之前不会运行" 这句话的意思我说一下吧。因为 JS 是单线程的,而 setTimeout 注册事件是队列的,setTimeout 放到队列之后,因为之前的 for
循环并没有执行完,所以不会立即执行 setTimeout 的。这也就是为什么说 JS 时间处理在线程空闲之前不会运行 的原因了。实际上 for 循环是这么走的:
PHP中文网2017-04-10 15:08:54
setTimeout会将函数放入队列,等待有机会让其执行。
队列:
- i++ // 2
- i++ // 3
- i++ // 4
- console.log(i) // 因为i 已经是4了,所以输出4
setTimeout:
setTimeout(function(){
console.log(i);
},0);
虽然函数等待了0秒,但是其实真正等到setTimeout中的匿名函数执行的时候,for循环的i已经从1变成了4。
所以得到的是4。
解决方法:通过闭包保存i,使之与匿名函数的i关联。
队列:
- i++ // 2
- (function(a){console.log(a)})(i) // 末尾的括号中传入i,保存现在i的值 2
- i++ // 3
- (function(a){console.log(a)})(i) // 末尾的括号中传入i,保存现在i的值 3
- i++ // 4
- (function(a){console.log(a)})(i) // 末尾的括号中传入i,保存现在i的值 4
等真正执行匿名函数时,i就是每个函数保存的值,而不是for循环i的最终值。
黄舟2017-04-10 15:08:54
Javascript是单线程运行的,在for循环及其所在的函数执行完毕前,setTimeout是没有机会执行的,就如 楼上 叙述,setTimout只是把需要执行的函数放在执行队列中等待排队执行而已
PHP中文网2017-04-10 15:08:54
额,看到你的解决方法...
for(var i=1;i<=3;i++){
setTimeout((function(a){ //改成立即执行函数
console.log(a);
})(i),0);
};
很有问题啊,是标准答案?
如果是用这个方法,setTimout
的存在一点必要都没有了,因为里面的console.log(a);
会马上执行,而不是setTimout
的序列等待结束之后才执行,你可以把时间设成5秒,看看,是不是马上就打印了。
改成这样会好一些
for(var i=1;i<=3;i++){
(function(a){
setTimeout(function(){ //改成立即执行函数
console.log(a);
},5000);
})(i)
}
高洛峰2017-04-10 15:08:54
不是setTimeout方法还可以向延迟函数传递额外参数的功能吗(尽管IE9及其之前的不兼容)。
for(var i=1;i<=3;i++){
setTimeout(function(a){
console.log(a);
},3000,i);
};