for (var i = 0; i < 3; i++) {
setTimeout(function() {
console.log(i);
}, 0);
console.log(i);
}
请教下这段代码的执行结果是多少,求一份指导过程。
先看结果,这段代码执行的时候是这个样子:
var i;
for (i=0; i < 3; i++){
console.log(i) //结果是0,1,2
}
console.log(i) // 3
console.log(i) // 3
console.log(i) // 3
原因是多个js的特性组成的:
1、 var i; 是因为js里面变量提前声明,这个很多面试题都会考到。
2、 setTimeout 机制,不会在主线程中执行, 而是放到event loop, 表示要等主线程的程序执行完了,才能开始执行 loop 里面的代码,也就是 3个 console放到了最后的原因
3、 变量的作用域,这个里面i的作用域包含了全部,所以最后的console时候,i的值已经变成了3
setTimeout()
是计划
在未来的某个时间点运行,之所以说“计划”是因为js是运行在单线程环境中的,虽然setTimeout()
是在语句之后立即开始计时,但是最差也必须等待主线程运行完毕才会去运行延时函数里面的代码。在这里,变量
i
的作用域是整个函数,当setTimeout()
内代码运行的时候,循环已经结束,此时i=3
,输出当然是3。如果你想要延时输出0、1、2,你需要用闭包来保存当前的
i
的值。
for(var i = 0; i < 3; i++) {
(function() {
var now = i;
setTimeout(function(){
console.log(now);
}, 0);
})();
console.log(i);
}
//如果是es6,有了块级作用域,就不需要用立即执行函数来隔绝作用域了,也可以直接这么写。
for(let i = 0; i < 3; i++) {
setTimeout(function(){
console.log(i);
}, 0);
console.log(i);
}
0
,1
,2
,3
,3
,3
当然是3啦,,JS的异步执行机制,setTimeout会将加入其中的事件放入到一个事件队列中去,等到所有代码执行完,再去事件队列中询问:“还有没有需要执行的事件呀?~”,然后事件队列就会依次出队列执行,此时的i是全局变量,已经变成3了,所以,打印出来也是3咯
settimeout是要等当前事件执行完之后马上执行,所以在循环中只是将它加入到事件队列中,等循环执行完之后才会调用。三次循环分别输出1,2,3而此时i=3.所以输出3
直接用Google的Console
执行你就知道了。如
var i;
for (i = 0; i < 3; i++) {
// 定时器会放在 event loop 里面,定时器到的时候触发事件,执行定时器里面的函数
// 执行定时器的函数时,js 主线程已经执行完毕,这时 i 已经设置为 3.
setTimeout(function() {
console.log(i);
}, 0);
// 上面的代码不会影响 js 主线程的执行,所以会先打印出 i。
console.log(i);
}