闭包的形成需同时满足嵌套定义、内部函数引用外部变量、外部持有内层函数三个条件。仅嵌套或仅访问变量不构成闭包;必须通过返回、赋值等方式使内层函数在外部存活,从而保留对外部变量的词法引用。

闭包不是靠“写成嵌套函数”就自动产生的,关键在于内部函数是否被外部作用域引用,同时又访问了外部函数的变量。
函数嵌套只是结构前提,不是充分条件
单纯写一个函数里面再定义一个函数,不会自动形成闭包。比如:
function outer() {let x = 10;
function inner() { console.log("hello"); } // 没引用 x
inner(); // 立即调用,没返回,也没传出去
}
这里 inner 没有引用 outer 的变量,也没有被外部拿到,outer 执行完,x 就被回收,不构成闭包。
必须满足三个动作:嵌套 + 引用 + 外带
闭包真正形成,需要三步同时发生:
- 外层函数中定义内层函数(嵌套结构)
- 内层函数体内直接使用外层函数的局部变量或参数(产生引用关系)
- 外层函数把内层函数作为返回值,或赋给全局变量、传给其他函数(让内层函数在外部环境存活)
例如:
function createAdder(base) {return function(num) { return base + num; }; // 引用了 base,且被返回
}
const add5 = createAdder(5); // base=5 被保留在 add5 的词法环境中
console.log(add5(3)); // 输出 8
外部引用阻止垃圾回收,保留词法环境
V8 引擎中,每个函数都有自己的词法环境,记录它创建时能访问哪些变量。当 inner 被返回并赋给外部变量时,它的词法环境链里仍保留着对 outer 变量环境的引用。即使 outer 执行结束、执行上下文被销毁,它的变量环境因被 inner 持有而无法回收。
这意味着:
- 每次调用 add5,都能通过词法环境链找到当初 createAdder(5) 时的 base
- 多个调用 createAdder 会生成多个独立的闭包,各自保存不同的 base 值
- 闭包不是共享变量,而是为每次外层函数调用“快照”一份私有环境
常见误判点:立即执行不算闭包
下面这段代码看起来嵌套,但不形成闭包:
function outer() {let count = 0;
function inner() { count++; }
inner(); // 内部调用,没传出,count 随 outer 结束而释放
}
只有 inner 被“带出去”并在之后调用,才激活闭包机制。核心不在“怎么写”,而在“谁持有、谁访问、谁延续生命周期”。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











