for循环相关
for(var i = 1; i <= 5; i ++){
console.log(i) // 1 2 3 4 5
}
观察以下代码:
for(var i = 1; i <= 5; i ++){
setTimeout(function timer(){
console.log(i) //5个 6
}, 0)
}
问题描述:
为什么会全部输出6?如何改进,让它输出1,2,3,4,5?
原因:
因为setTimeout为宏任务,由于JS中单线程eventLoop机制,在主线程同步任务执行完后才去执行宏任务,因此循环结束后setTimeout中的回调才依次执行,但输出
i 的时候当前作用域没有,往上一级再找, 发现了 i ,此时循环已经结束,i 变成了6。因此会全部输出6。
解决方法:
1、利用IIFE(立即执行函数表达式)当每次for循环时,把此时的i变量传递到定时器中
for(var i = 1;i <= 5;i++){
(function(j){
setTimeout(function timer(){
console.log(j)
}, 0)
})(i)
}
2、给定时器传入第三个参数, 作为timer函数的第一个函数参数
for(var i=1;i<=5;i++){
setTimeout(function timer(j){
console.log(j)
}, 0, i)
}
3、使用ES6中的let
for(let i = 1; i <= 5; i++){
setTimeout(function timer(){
console.log(i)
},0)
}
let使JS发生革命性的变化,让JS有函数作用域变为了块级作用域,用let后作用域链不复存在。代码的作用域以块级为单位,以上面代码为例:
// i = 1
{
setTimeout(function timer(){
console.log(1)
},0)
}
// i = 2
{
setTimeout(function timer(){
console.log(2)
},0)
}
// i = 3
...
因此能输出正确的结果1,2,3,4,5。