什么是闭包

闭包定义
在JavaScript中,内层函数引用外层函数作用域的变量/函数,且内层函数被外部访问,导致外层函数执行完后,其作用域不会被销毁,这种"函数+其关联的作用域"组合称为闭包。
核心特征:
- 延长变量的生命周期;
- 私有化变量(避免全局污染)。
核心示例
javascript
function outer() {
const privateVar = '私有变量'; // 外层函数变量
// 内层函数引用外层变量
function inner() {
console.log(privateVar);
}
return inner; // 内层函数被外部访问
}
const fn = outer();
fn(); // 输出:私有变量(outer执行完后,privateVar仍被保留)
适用场景
- 私有化变量/方法:模拟类的私有属性(JavaScript无原生私有属性)。
javascript
const Counter = (() => {
let count = 0; // 私有变量,外部无法直接访问
return {
increment: () => count++,
decrement: () => count--,
getCount: () => count
};
})();
Counter.increment();
console.log(Counter.getCount()); // 1
console.log(Counter.count); // undefined(无法直接访问)
- 缓存数据:如计算结果缓存(避免重复计算)。
javascript
function createCalculator() {
const cache = {}; // 缓存计算结果
return {
add: (a, b) => {
const key = `${a}+${b}`;
if (cache[key]) return cache[key];
const result = a + b;
cache[key] = result;
return result;
}
};
}
const calc = createCalculator();
console.log(calc.add(1, 2)); // 3(计算并缓存)
console.log(calc.add(1, 2)); // 3(直接取缓存)
- 防抖/节流函数:依赖闭包保存定时器ID/触发时间。
javascript
// 防抖函数(闭包实现)
function debounce(fn, delay) {
let timer = null; // 闭包保存定时器ID
return (...args) => {
clearTimeout(timer);
timer = setTimeout(() => fn.apply(this, args), delay);
};
}
// 节流函数(闭包实现)
function throttle(fn, interval) {
let lastTime = 0; // 闭包保存上次执行时间
return (...args) => {
const now = Date.now();
if (now - lastTime >= interval) {
fn.apply(this, args);
lastTime = now;
}
};
}
- 事件监听/回调:保留上下文变量。
javascript
function bindEvent() {
const btn = document.getElementById('btn');
const msg = '点击成功'; // 闭包保留msg
btn.addEventListener('click', () => {
alert(msg);
});
}
bindEvent();
注意事项
1.闭包会导致变量长期驻留内存,滥用可能导致内存泄漏(需手动释放,如将引用置为null)。
2.循环引用问题: 闭包与DOM元素互相引用可能导致内存泄漏。
3.数据元素遍历中,频繁创建闭包可能影响性能。
4.多层嵌套闭包导致作用域链查找变慢。
- 变量意外共享问题: 循环中创建闭包时的经典问题