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

JS闭包示例解析:let循环变量的闭包求值疑问

搞懂var和let在for循环里的作用域差异

首先先快速回顾你提到的var的情况,帮咱们对比着看:

function createFunctionsWithVar() {
  var arr = [];
  for (var i = 0; i < 5; i++) {
    arr.push(function() { console.log(i); });
  }
  return arr;
}

const funcsVar = createFunctionsWithVar();
funcsVar[0](); // 输出5,所有函数都共享同一个i

这是因为var的作用域是函数级的,整个循环里只有一个i变量,所有push进去的函数都捕获的是这个同一个i的引用。当循环结束时i已经变成5,所以后续调用任何函数都会输出5。

接下来重点说你困惑的let的情况:
你觉得“此时i已无定义”其实是个误解,咱们看实际运行的代码:

function createFunctionsWithLet() {
  let arr = [];
  for (let i = 0; i < 5; i++) {
    arr.push(function() { console.log(i); });
  }
  return arr;
}

const funcsLet = createFunctionsWithLet();
funcsLet[0](); // 输出0
funcsLet[1](); // 输出1
funcsLet[2](); // 输出2
funcsLet[3](); // 输出3
funcsLet[4](); // 输出4

为什么会这样?这是ES6给let(还有const)在for循环头部声明时设计的特殊绑定规则:

  • 每次循环迭代,JavaScript都会为i创建一个全新的变量绑定,而不是像var那样复用同一个变量。
  • 每个push到数组里的函数,捕获的都是当前迭代的那个专属的i引用。
  • 当后续调用这些函数时,它们会从自己捕获的词法环境中取出对应的i值,也就是当时循环迭代时的数值,所以能正确输出0到4,根本不会出现“i无定义”的情况。

简单说,let在for循环头部的行为,相当于把变量的作用域缩小到了每一次循环迭代的块级作用域里,每个迭代的i都是独立的,闭包自然就能保存住对应的值了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 10:16:32