闭包是内部函数在定义时绑定其词法作用域,从而捕获并持久化外部函数变量的机制;需满足嵌套声明、引用外部变量、脱离外部作用域三条件。

闭包保存函数的执行环境,本质是让内部函数“绑定”它被定义时所处的词法作用域,而不是等它执行时才去查找。这个环境包括外部函数的局部变量、参数,甚至其他内部函数——只要内部函数引用了它们,JS 引擎就会把整个作用域链的一部分长期保留在内存中。
闭包如何捕获并锁定执行环境
关键不在“执行时”,而在“定义时”。JavaScript 采用词法作用域,函数在写好那一刻就决定了它能看到哪些变量。当内部函数被返回或传出外部函数作用域后,它仍带着对原始环境的引用,这个引用阻止了垃圾回收机制清理掉那个环境。
- 外部函数执行时会创建一个**活动对象(AO)** 或**词法环境记录**,存放其所有局部变量;
- 内部函数在定义时,会被赋予一条**作用域链**,其中包含对外部函数词法环境的引用;
- 一旦内部函数脱离外部函数作用域(比如被 return 出来),只要它还存在(被变量持有、作为回调传入事件监听器等),它所引用的那部分环境就不会被释放。
一个典型例子:记住计数器状态
下面这段代码里,inner 不仅记住了 count 的初始值,更持续维护着它的变化过程:
function outer() {let count = 0;
function inner() {
count++;
return count;
}
return inner;
}
const inc = outer();
inc(); // 1
inc(); // 2
inc(); // 3
每次调用 inc(),其实都在操作同一个 count 变量——它不属于全局,也不属于 inc 自身的作用域,而是来自 outer 执行时生成的那个已被“冻结”的环境。
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
立即学习“Java免费学习笔记(深入)”;
闭包保存环境的三个硬性条件
只有同时满足以下三点,才会真正形成闭包并持久化环境:
- 存在嵌套函数结构(内部函数在外部函数体内声明);
- 内部函数实际引用了外部函数的变量(哪怕只读);
- 内部函数以某种方式脱离了外部函数作用域(如被返回、赋值给全局变量、传入 setTimeout/setInterval 等异步上下文)。
注意:不是所有嵌套都等于闭包
如果内部函数没被传出,或者根本没引用外部变量,那它只是普通嵌套,不会延长外部变量的生命周期。例如:
function f() {let x = 10;
function g() { console.log("hi"); } // 没引用 x
g(); // 立即调用,不返回
}
这种情况下,f 执行完,x 就会被正常回收——没有闭包产生。

















