话不多说先上代码
for (var i = 0; i < 10; i++) {
setTimeout(() => {
console.log(i)
}, 0)
}
这道题的答案输出结果是10个10!
加点打印输出
for (var i = 0; i < 10; i++) {
console.log("先执行同步任务")
setTimeout(() => {
console.log("再执行异步宏任务")
console.log(i)
}, 0)
}
原因 :
首先,js中的var是全局变量,在循环中定义的i,在循环外也是可以访问到的,这个读者可以自己测试一下。其次,循环体本身是一个同步任务,而定时器是异步任务,定时器属于异步任务中的宏任务,在执行的时候首先是执行完十次循环之后,才去执行宏任务队列中的十个宏任务,这样就导致执行定时器中的代码的时候,全局变量i的值已经是10了,所以后面访问到的都是10.。
不明白什么是宏任务和微任务可以看我之前的博客
详解宏任务和微任务
解决方案1
将var换成let
for (let i = 0; i < 10; i++) {
setTimeout(() => {
console.log(i)
}, 0)
}
说明:
let形成的是块级作用域,这样在每次定时器输出的时候,i的值不会相互干扰。每一个都是一个独立的i。
解决方案2
那么要想输出0-9如何实现呢,首先想到的是闭包,闭包的功能很强大,通过闭包形成一块独立的作用域,不受外部干扰。
for (var i = 0; i < 5; i++) {
console.log("先执行同步任务1");
(function(j){
setTimeout(() => {
console.log("再执行异步宏任务")
console.log(j)
}, 0)
console.log("执行同步任务2")
}
)(i)
}
说明
在执行完第一个同步任务之后,执行函数中的立即执行函数,立即执行函数体内生成一个异步宏任务,宏任务排到宏任务队列中等待同步任务执行,所以执行同步任务2。宏任务执行的时候使用的是立即执行函数传入的参数,形成闭包。
个人理解,若有错误还请大佬指出。