函数在定义时就确定了它能访问哪些变量,这条链由定义位置决定,而不是调用位置。闭包就是函数带着这条链一起被保存下来。
闭包是函数记住了外层变量
JavaScript
function createCounter() {
let count = 0;
return {
increment() {
count += 1;
return count;
},
current() {
return count;
},
};
}
const counter = createCounter();
counter.increment(); // 1
counter.increment(); // 2createCounter 执行完后,它的局部作用域按理应该被回收,但因为返回的两个函数还引用着 count,这个变量被保留了下来。count 变成了外部无法直接修改、只能通过方法访问的状态。
什么时候会意外留住内存
闭包保留的是变量本身,只要闭包还被引用,变量就不会释放。定时器、事件监听、缓存对象里保存了闭包却没清理,就会让本该释放的数据一直占着内存。
- 定时器回调引用了大对象,清理时记得 clearInterval
- 事件监听在组件卸载时没有移除
- 用闭包做缓存时没有设置上限
在真实代码里的两种用法
- 封装私有状态:模块内部可写,外部只能通过暴露的方法读写
- 保存配置与上下文:事件回调需要用到注册时的变量,而不是触发时的变量
闭包不是需要刻意制造的东西,它只是作用域规则自然产生的结果。


