You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 07:06:19