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

JS中for循环搭配setTimeout用var输出3次3、用let修复的原理求解

JS for循环搭配setTimeout的变量绑定原理说明

原始var声明代码输出3次3的原因

原始代码如下:

for (var i = 0; i < 3; i++) {
  setTimeout(function log() {
    console.log(i); // What is logged?
  }, 1000);
}

var声明的变量不存在块级作用域,上述代码里的i属于外层作用域(全局环境下就是window.i)的同一个变量,整个for循环过程中只会修改这一个i的值。
setTimeout是异步宏任务,会等到同步的for循环完全执行完毕后才会触发回调。此时for循环已经完成终止判断,i的值已经被更新为3,三个setTimeout的回调log函数捕获的都是同一个外层作用域的i,所以会连续输出三次3。

替换为let后输出0、1、2的核心原因

你猜测的let支持块级作用域是完全正确的,这里的关键特性是:for循环头部用let声明的迭代变量,每次循环都会创建一个独立的块级作用域,同时将当前迭代的i值拷贝到这个块级作用域中。
也就是说三次循环实际生成了三个互不干扰的独立块级作用域,每个作用域里存储的i值分别是0、1、2,每个setTimeout的log函数捕获的是对应块级作用域里的独立i,所以异步触发时会按顺序输出0、1、2。

其他等价实现方案

如果运行环境不支持ES6的let,也可以用立即执行函数(IIFE)手动为每次循环创建独立作用域存值,效果和使用let完全一致:

for (var i = 0; i < 3; i++) {
  // 每次循环将当前i作为参数传入IIFE,创建独立作用域存值
  (function (currentI) {
    setTimeout(function log() {
      console.log(currentI);
    }, 1000);
  })(i);
}

内容的提问来源于stack exchange,提问作者notADevYet

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.26 11:54:00