函数作用域和块级作用域
大约 1 分钟
相关信息
问题:
// 这段代码为什么会输出五个5呢,执行顺序和逻辑有是什么样的呢
for (var i = 0; i < 5; i++) {
setTimeout(function() {
console.log(i); // 输出5个5
}, 100);
}为什么输出五个5?
这段代码的输出结果确实会打印五个数字5,而不是预期的0,1,2,3,4。这是由于JavaScript的变量作用域和事件循环机制共同作用的结果。
执行顺序和逻辑分析
1、变量作用域问题:
使用var声明的变量i是函数作用域的,而不是块级作用域的
在整个代码中只有一个i变量,它在循环结束后值为5
2、事件循环机制:
setTimeout是异步的,回调函数会在当前执行栈完成后执行
循环会先快速执行完(同步代码),此时i已经变为5
然后所有setTimeout的回调函数才开始执行,此时它们访问的都是同一个i,其值为5
3、时间线:
同步代码执行:循环快速完成,i从0递增到5
异步回调执行:100毫秒后,所有5个回调函数开始执行,打印当前的i值(此时已经是5)
如何修复这个问题?
1、使用let声明变量(块级作用域):
for (let i = 0; i < 5; i++) {
setTimeout(function() {
console.log(i); // 输出0,1,2,3,4
}, 100);
}2、使用闭包(IIFE):
for (var i = 0; i < 5; i++) {
(function(j) {
setTimeout(function() {
console.log(j); // 输出0,1,2,3,4
}, 100);
})(i);
}3、使用setTimeout的第三个参数:
for (var i = 0; i < 5; i++) {
setTimeout(function(j) {
console.log(j); // 输出0,1,2,3,4
}, 100, i);
}