异步JavaScript中let声明变量时do/while与for循环输出不一致原因探究
为什么do/while与for循环搭配setTimeout会输出不同结果?
先看这段do/while循环的代码:
function logNum() { let counter = 0; do { counter += 1; setTimeout(() => console.log(counter), counter * 1000); } while(counter <= 10); } logNum();
这段代码运行后会连续10次输出11,但预期效果是依次输出1到10。
再看for循环的实现版本:
function logNum() { for (let counter = 1; counter <= 10; counter += 1) { setTimeout(() => console.log(counter), counter * 1000); } } logNum();
这个版本却能按预期依次输出1到10,差异的核心原因如下:
核心原因:let在循环中的作用域绑定差异
- do/while循环场景:
counter是在循环外部声明的,整个循环周期内只有这一个counter变量。setTimeout的回调是异步执行的,等所有回调触发时,循环早已执行完毕,此时counter的值已经变为11,所以所有回调都会输出这个最终值。 - for循环场景:用
let声明的循环变量,会在每一轮迭代时创建一个全新的变量绑定。也就是说,每一次循环的counter都是独立的,setTimeout的回调会捕获当前迭代对应的那个counter值,因此最终能依次输出1到10。
do/while循环的修正方案
要让do/while循环达到预期效果,需要在每次迭代中创建独立变量保存当前counter的值,避免回调捕获到循环结束后的最终值:
function logNum() { let counter = 0; do { let num; counter += 1; num = counter; setTimeout(() => console.log(num), num * 1000); } while(counter < 10); } logNum();
这里每轮迭代都会声明新的num变量,保存当前counter的快照值,回调函数捕获的是这个独立的num,因此能正确输出对应数值。
内容的提问来源于stack exchange,提问作者noSelf_
相关产品推荐
相关产品推荐

