闭包捕获的是变量的绑定(内存位置)而非值,执行时读取该位置当前值;let每次迭代新建绑定故表现如“快照”,var共享绑定故表现如“实时”。

JavaScript 中闭包捕获外部变量,既不是“实时读取”,也不是“一次性快照”,而是在函数定义时确定变量的绑定位置(词法环境),在执行时按需访问该绑定所指向的当前值。这个行为常被误解为“快照”或“实时”,但本质是词法作用域 + 变量绑定 + 值动态解析的组合结果。
闭包不保存变量的值,只保留对变量的引用
闭包内部函数记住的是外层作用域中变量的内存位置(绑定),而非当时的值。只要该变量仍存活(比如被闭包持有),后续每次调用闭包都会读取该位置当前存储的值。
- 对于 let/const 声明的块级变量,每次循环迭代会创建新绑定(如 for 循环中),因此每个闭包捕获的是独立的绑定 → 表现像“快照”
- 对于 var 声明的变量,整个作用域共享一个绑定 → 所有闭包共享同一变量 → 表现像“实时”(但其实是反复读同一个地址)
经典例子:for 循环中的 i
对比两种声明方式:
✅ let(推荐)—— 每次迭代新建绑定for (let i = 0; i console.log(i), 100); // 输出 0, 1, 2 }
每个回调闭包捕获的是各自迭代中独立的 i 绑定,互不影响。
for (var i = 0; i console.log(i), 100); // 输出 3, 3, 3 }
所有回调都引用同一个 i,循环结束时 i === 3,所以都输出 3。
闭包中的变量是否会被修改?
可以。如果闭包内对外部变量重新赋值(且该变量可写),会影响所有共享该绑定的其他代码:
-
let/const变量在闭包内不可重新声明,但let可赋值(const不可) -
var和let声明的变量,若在闭包中执行x = newValue,会改变原始绑定的值 - 这种修改对其他同样引用该绑定的函数可见(比如多个闭包共享同一外层变量)
如何真正实现“值快照”?
如果确实需要捕获某个时刻的值(比如避免异步中变量变化干扰),可通过以下方式显式固化:
- 立即执行函数(IIFE)传参:
(function(val) { return function() { console.log(val); }; })(i) - 箭头函数参数绑定:
arr.map((x, i) => () => console.log(i))(参数 i 是每次调用时的副本) - 使用
let配合块级作用域(最简洁自然)
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











