问题引出:下面的代码输出结果什么?
for (var i = 0; i < 5; i++) {
setTimeout(() => {
console.log(i);
}, 1000);
}
答案:6个5。
解析:根本原因是在这段代码中,var关键字的作用域是函数作用域。
外层的for循环一共执行了五次,生成了五个定时器,每个定时器输出变量i的值。相当于如下的代码:
{
var i = 0;
setTimeout(() => {
console.log(i);
});
}
{
var i = 1;
setTimeout(() => {
console.log(i);
});
}
{
var i = 2;
setTimeout(() => {
console.log(i);
});
}
{
var i = 3;
setTimeout(() => {
console.log(i);
});
}
{
var i = 4;
setTimeout(() => {
console.log(i);
});
}
{
var i = 5;
}
js中同步代码块先执行,所以当定时器执行的时候,i变量已经变成5了,又由于var关键字的函数作用域,所以所有的定时器输出的结果都是5。
如果将上述var关键字改成let关键字,则代码会依次输出0,1,2,3,4。
for (let i = 0; i < 5; i++) {
setTimeout(() => {
console.log(i);
}, 1000);
}
这是因为let关键字是块级作用域,所以上述代码的拆分是这样的:
{
let i = 0;
setTimeout(() => {
console.log(i);
}, 1000);
}
{
let i = 1;
setTimeout(() => {
console.log(i);
}, 1000);
}
{
let i = 2;
setTimeout(() => {
console.log(i);
}, 1000);
}
{
let i = 3;
setTimeout(() => {
console.log(i);
}, 1000);
}
{
let i = 4;
setTimeout(() => {
console.log(i);
}, 1000);
}
{
let i = 5;
}
每个定时器只读取块级作用域中的i,自然会依次输出01234。