闭包捕获的是变量的绑定(内存地址)而非值。它记录变量在定义时的词法作用域引用,执行时读取该地址的当前值;多个闭包共享同一变量时会看到相同值,所谓“快照”实为let每次迭代新建绑定所致。

闭包不是拍下变量值的“照片”,而是记住了变量在哪儿——它捕获的是变量的绑定(内存位置),不是当时的值。所谓“快照感”,其实是语言机制(比如 let 每次迭代新建绑定)带来的副作用,不是闭包本身在复制值。
闭包真正捕获的是什么?
闭包内部函数在定义时,就绑定了外层作用域中变量的引用地址。后续每次执行,都去这个地址读取当前值。变量没被销毁,是因为闭包还拿着它的“门牌号”,垃圾回收器不敢动它。
- 不是值拷贝:改了闭包里的变量,原变量也跟着变(可写时)
- 不是动态查找:不依赖调用时的外部环境,只认定义时的词法作用域
- 不是自动隔离:多个闭包若引用同一变量,它们看到的是同一个值(除非语言强制新建绑定)
为什么有时像“快照”?关键在变量声明方式
表现差异来自变量绑定的生命周期,和闭包无关:
- let/const 在块级作用域(如 for 循环每次迭代)创建新绑定 → 每个闭包拿到不同地址 → 看起来像各自存了一份值
- var 全局共享一个绑定 → 所有闭包指向同一地址 → 循环结束时读到最终值(如 i=3)
想真正固化值?得手动做
如果业务需要某次循环的值“定格”,不能靠闭包自动完成,得显式传参或封装:
- 用 let 声明循环变量(最简、推荐)
- 立即执行函数传入当前值:
(function(val) { return () => console.log(val); })(i) - 箭头函数参数绑定:
arr.map((x, i) => () => console.log(i))
闭包的本质是环境打包,不是值快照
它把函数体和它定义时能访问的所有外部变量“打成一个包”。这个包里装的是行为(代码)+ 状态(变量引用),两者不可拆分。所谓“快照错觉”,只是你恰好用了 let,让每个包拿到了不同的状态入口而已。

















