JavaScript中setTimeout循环输出不同结果原因解析
JS循环中定时器输出差异问题解释
连续5次打印4的原因
对应代码如下:
let number = 1; for (var i=0; i<5; i++){ number=i; setTimeout(()=>{ console.log(number) },1000) }
核心逻辑:
- JS执行时同步任务优先,
setTimeout的回调属于异步宏任务,会被暂存到任务队列,必须等所有同步代码执行完毕才会开始运行。 - 这里的
number是声明在循环外层的唯一变量,for循环作为同步任务会连续执行:每一轮循环都把number重新赋值为当前的i值,等循环完全跑完时,i最后一次进入循环的值是4,number的最终值就停在4。 - 1秒延迟到点后,5个定时器回调几乎同时触发,所有回调读取的都是同一个外层
number变量,拿到的都是最终值4,因此连续打印5次4。
连续5次打印5的原因
对应代码如下:
for (var i=0; i<5; i++){ setTimeout(()=>{ console.log(i) },1000) }
核心逻辑:
- 用
var声明的变量不存在块级作用域,整个for循环从头到尾都共享同一个全局i变量。 - 同步循环执行时,i会从0开始逐次累加,直到i等于5时不再满足
i<5的循环条件,循环才会终止,此时这个全局i的最终值就是5。 - 等定时器回调触发时,所有回调读取的都是这同一个全局i,拿到的都是循环结束后的最终值5,因此连续打印5次5。
var替换为let后依次打印0-4的原因
对应代码如下:
for (let i=0; i<5; i++){ setTimeout(()=>{ console.log(i) },1000) }
核心逻辑:
let声明的变量存在块级作用域,ES6规范对for循环中的let声明做了专门设计:每一轮循环都会生成一个独立的块级作用域,每个作用域都会单独保存当前轮次的i值。- 简单说就是5轮循环对应5个完全独立的i变量,分别存储了0、1、2、3、4五个值。
- 定时器的箭头函数在定义时,会捕获自身所在块级作用域里的i,等延迟到点回调执行时,每个回调读取的都是自己对应轮次保存的独立i值,因此会依次打印0到4。
内容的提问来源于stack exchange,提问作者Ashwani Panwar
相关产品推荐
相关产品推荐

