闭包在内部函数定义完成时即产生,持续存在直至其函数对象失去所有外部引用才结束;它不依赖函数调用或外部函数返回,而取决于是否仍有变量持有对该函数的引用。

JavaScript 闭包的生命周期不取决于函数是否被调用,而取决于内部函数对象是否还被持有引用。它从内部函数定义完成时就已产生,直到该函数对象失去所有外部引用、变成垃圾对象时才真正结束。
闭包产生的准确时机
闭包在嵌套的内部函数**定义执行完毕时**就已形成,不是在调用时,也不是在外部函数返回时。这是因为 JavaScript 存在函数提升(function hoisting):只要语法上存在函数声明,引擎就会在预编译阶段为其创建函数对象并绑定词法环境。
- 即使内部函数从未被调用,只要它被声明(非表达式形式),且引用了外部作用域变量,闭包就已经存在
- 例如:
function outer() { const x = 1; function inner() { return x; } }——inner函数对象一创建,就捕获了outer的词法环境,闭包即刻生成 - 使用函数表达式(如
const inner = function() { ... })时,闭包在该表达式求值完成时产生
闭包持续存在的必要条件
闭包能“活下来”,关键在于**内部函数对象必须被至少一个变量持续引用**。一旦外部函数执行结束,其执行上下文销毁,局部变量本该被回收;但若这些变量被闭包引用,且闭包本身仍被持有,变量就会继续驻留堆内存。
- 典型做法是让外部函数
return内部函数,并用一个变量接收它,如const fn = outer() - 这个变量
fn保存的是内部函数的内存地址,使函数对象不会被垃圾回收器标记为可回收 - 其他方式同样有效:赋值给全局属性、存入数组/对象、作为事件监听器绑定等,只要存在强引用即可
闭包何时真正死亡
闭包死亡的标志是:**包含它的内部函数对象彻底失去所有引用,成为垃圾对象**。此时 JavaScript 引擎的垃圾回收器(GC)会在下一次运行时将其连同所捕获的变量一并释放。
立即学习“Java免费学习笔记(深入)”;
- 常见操作是显式切断引用,比如
fn = null、delete obj.fn或让引用它的变量超出作用域 - 注意:仅调用闭包函数(如
fn())不会导致闭包死亡;多次调用反而说明它仍在活跃使用中 - 若忘记解除引用(尤其在长期存活的对象或事件监听中),闭包会持续占用内存,引发内存泄漏
实际例子中的生命周期节点
以计数器为例:
const createCounter = () => {
let count = 0;
return () => ++count;
};
const inc = createCounter(); // ✅ 此时闭包已产生(内部箭头函数定义完成)
inc(); // 1 → 闭包正在使用
inc(); // 2 → 闭包仍在使用
inc = null; // ✅ 此时内部函数对象失去引用,闭包进入待回收状态
从 createCounter 执行完,到 inc = null 这一刻,就是这个闭包完整的生命跨度。


















