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

let声明变量的箭头函数闭包捕获策略差异原因探究

为什么两段闭包代码输出结果不同?

这问题真的戳中了 JavaScript 闭包和let作用域的关键细节,很多开发者第一次碰到都会困惑,我来给你拆解清楚:

首先明确核心前提:JavaScript 的闭包确实是捕获变量的引用,但两段代码的差异,本质是被捕获的变量本身的绑定方式完全不一样。

第一段代码:for 循环内用let声明变量

arr = [];
for(let i = 0; i < 3; i++) {
  arr.push(() => console.log(i));
}
arr.forEach(ele => ele());

这里的let i写在 for 循环的初始化语句里,这是 ECMAScript 标准专门做的特殊处理:每次循环迭代时,都会创建一个全新的i变量实例。也就是说:

  • 第一次循环(i=0):创建一个值为0的i变量,闭包捕获这个变量的引用
  • 第二次循环(i=1):再创建一个全新的i变量(和上一个完全独立),值为1,闭包捕获这个新变量的引用
  • 第三次循环(i=2):又创建一个全新的i变量,值为2,闭包捕获这个变量的引用

当你后续调用数组里的三个函数时,每个函数对应的都是各自迭代时的那个i变量,所以会依次输出0,1,2。

第二段代码:循环外声明let j

arr = [];
let j;
for(j = 0; j < 3; j++) {
  arr.push(() => console.log(j));
}
arr.forEach(ele => ele());

这里的j是在循环外部声明的,整个循环过程中只有一个j变量存在,每次循环只是更新这个变量的值:

  • 循环开始时 j=0,闭包捕获这个 j 的引用
  • 循环到 j=1,还是同一个 j 变量,值被更新,闭包依然指向这个变量
  • 循环到 j=2,同样是同一个 j,值更新为2
  • 循环结束后,j 的值会变成3(最后一次 j=2 时,j++后等于3,不满足 j<3 的条件,循环终止)

当你调用数组里的函数时,三个闭包捕获的都是同一个 j 变量的引用,而此时 j 的值已经是3了,所以三个函数都会输出3。

额外补充:换成var会怎样?

如果把第一段代码的let i换成var i,输出结果会和第二段一样都是3,3,3。因为var没有块级作用域,整个循环里只有一个i变量,闭包捕获的都是这个变量的引用,循环结束后 i 的值是3,所以调用函数时都会打印3。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.28 23:08:14