跳到主要内容

闭包有哪些表现形式?

面试速答(30 秒版 TL;DR)

  • 闭包不是“某种语法”,而是函数引用了外层自由变量时自然形成的机制。
  • 常见表现:返回函数、回调函数、IIFE(立即执行函数)创建私有状态、模块模式、多个函数共享同一份外层状态。
  • 判断口诀:只要函数用到了“不是自己作用域里声明的变量”,就是闭包

1) 返回函数(函数工厂)

function makeAdder(a) {
return function add(b) {
return a + b;
};
}

const add10 = makeAdder(10);
add10(5); // 15

add 用到了 a,而 a 来自外层 makeAdder,所以 add10 是闭包。


2) 回调/异步(定时器、事件、Promise)

function start() {
const label = "task-1";
setTimeout(() => {
console.log(label);
}, 100);
}
start();

setTimeout 的回调稍后执行,但仍访问 label,因此形成闭包。


3) IIFE 创建私有状态(模块模式)

const store = (() => {
let x = 0;
return {
inc() {
x += 1;
return x;
},
get() {
return x;
},
};
})();

store.inc(); // 1
store.get(); // 1

外部拿不到 x,但通过方法读写它:这是闭包实现“私有变量”的经典用法。


4) 多个函数共享同一份外层状态

function makeBox() {
let v = 0;
return {
set(x) {
v = x;
},
get() {
return v;
},
};
}

const b = makeBox();
b.set(42);
b.get(); // 42

set/get 都闭包引用同一个 v,所以能共享状态。


5) 常见面试陷阱:不是所有“函数里访问变量”都是闭包

  • 访问全局变量不算“捕获外层局部变量”的典型闭包点,但从定义上讲它依然使用了自由变量。
  • 访问 this 不是闭包:this 的绑定规则是动态的(由调用方式决定),不等同于词法环境捕获。

更稳的口径:闭包讨论重点是“捕获外层词法变量”。


易错点/坑

  • 把“回调”跟“闭包”画等号:回调不一定用到外层变量;用到了才是闭包问题的核心。
  • 把“闭包 = 内存泄漏”画等号:闭包只是延长生命周期,是否泄漏取决于引用是否被长期持有。

速记要点(可背诵)

  • 表现形式:return 函数、回调/异步、IIFE 模块、共享状态对象。
  • 判断:函数用到了外层自由变量。