问题引出:下面的代码输出结果什么?
for (var i = 0; i < 5; i++) {setTimeout(() => {console.log(i);}, 1000);
}
答案:6个5。
解析:根本原因是在这段代码中,var关键字的作用域是函数作用域。
外层的for循环一共执行了五次,生成了五个定时器,每个定时器输出变量i的值。相当于如下的代码:
javascript">{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。
javascript">for (let i = 0; i < 5; i++) {setTimeout(() => {console.log(i);}, 1000);
}
这是因为let关键字是块级作用域,所以上述代码的拆分是这样的:
javascript">{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。