闭包形成的关键是内部函数保留对外部函数局部变量的引用,即使外部函数已执行完毕;需同时满足:存在嵌套函数、该函数被返回或传出、且实际访问外部局部变量。

函数作为返回值是 JavaScript 中创建闭包最典型、最常用的方式。关键不在于“怎么写”,而在于“为什么能形成闭包”——核心是:内部函数保留了对外部函数作用域中变量的引用,即使外部函数已经执行完毕。
闭包产生的必要条件
必须同时满足三点:
- 存在一个内部函数(嵌套在另一个函数中)
- 该内部函数被返回(或以其他方式传出外部作用域)
- 内部函数实际访问了外部函数的局部变量(不只是参数或全局变量)
标准写法与执行过程
看这个例子:
function createCounter() {
let count = 0;
return function() {
count++;
return count;
};
}
const counter = createCounter();
console.log(counter()); // 1
console.log(counter()); // 2
执行时发生的事:
-
createCounter() 执行一次,生成独立的
count变量(私有状态) - 返回的匿名函数“记住了”它诞生时的词法环境,包括这个
count - 后续每次调用
counter(),操作的都是同一个count,不是重新声明
为什么变量没被销毁?
普通函数执行完,它的执行上下文(含变量对象)会被引擎回收。但一旦有内部函数对外部变量形成引用,JS 引擎会识别这种依赖关系,将相关变量保留在内存中——这就是闭包维持的“活环境”。
换句话说:不是函数本身特殊,而是它携带的词法环境被持续持有。
常见误区提醒
- 只返回函数但没访问外部变量 → 不算真正闭包(比如
return function(){ return 42; }) - 用
var声明 + 循环中返回函数 → 容易所有函数共享同一个变量(如经典的i问题),应改用let或立即执行函数捕获当前值 - 误以为“函数嵌套就一定有闭包” → 必须有“引用逃逸”,即内部函数被传出并可能后续调用











