一、闭包是什么?一个简单的例子
function outer() {
let me = '小杨';
return function inner() {
console.log(`大家好,我是${me}`);
};
}
const sayHello = outer();
sayHello();
看到没?inner
函数记住了outer
函数的me
变量,这就是闭包!
二、闭包的三大妙用(天使面)
1. 创建私有变量
function createCounter() {
let count = 0;
return {
increment() { count++ },
getCount() { return count }
};
}
const counter = createCounter();
counter.increment();
console.log(counter.getCount());
console.log(counter.count);
2. 实现函数柯里化
function multiply(a) {
return function(b) {
return a * b;
};
}
const double = multiply(2);
console.log(double(5));
3. 事件处理中的妙用
function setupButtons() {
for(var i = 1; i <= 3; i++) {
(function(index) {
document.getElementById(`btn-${index}`)
.addEventListener('click', function() {
console.log(`我是按钮${index}`);
});
})(i);
}
}
三、闭包的三大坑(魔鬼面)
1. 内存泄漏
function leakMemory() {
const bigData = new Array(1000000).fill('*');
return function() {
console.log('我还记得bigData');
};
}
const leaked = leakMemory();
2. 性能问题
function slowPerformance() {
const data = {};
return function(key, value) {
data[key] = value;
};
}
3. 意外的变量共享
function createFunctions() {
let funcs = [];
for(var i = 0; i < 3; i++) {
funcs.push(function() {
console.log(i);
});
}
return funcs;
}
四、闭包优化六大法则(6年经验总结)
1. 及时释放引用
function createHeavyObject() {
const heavy = new Array(1000000).fill('*');
return {
useHeavy: function() {
},
cleanup: function() {
heavy = null;
}
};
}
2. 使用块级作用域
function createFixedFunctions() {
let funcs = [];
for(let i = 0; i < 3; i++) {
funcs.push(function() {
console.log(i);
});
}
return funcs;
}
3. 避免不必要的闭包
function unneededClosure() {
const data = {};
return function() {
console.log('Hello');
};
}
function noClosure() {
console.log('Hello');
}
4. 使用WeakMap管理私有变量
const privateData = new WeakMap();
class MyClass {
constructor() {
privateData.set(this, {
secret: '我是私有数据'
});
}
getSecret() {
return privateData.get(this).secret;
}
}
5. 合理使用IIFE
(function() {
const tempData = processData();
})();
6. 使用模块化
const counterModule = (function() {
let count = 0;
return {
increment() { count++ },
getCount() { return count }
};
})();
五、真实案例分享
案例1:我曾经在项目中遇到一个页面卡顿问题,最后发现是因为一个事件处理函数形成了闭包,持有了一个大DOM树的引用。解决方案是:
function setup() {
const bigElement = document.getElementById('big');
button.addEventListener('click', function() {
console.log(bigElement.id);
});
}
function setup() {
const id = 'big';
button.addEventListener('click', function() {
console.log(id);
});
}
六、总结
闭包就像一把双刃剑:
✅ 优点:实现私有变量、函数柯里化、模块化等
❌ 缺点:可能导致内存泄漏、性能问题
记住我的6年经验总结:
- 及时释放不再需要的引用
- 优先使用块级作用域
- 避免不必要的闭包
- 合理使用WeakMap和模块化
- 善用开发者工具检查内存
转自https://juejin.cn/post/7512259761196957707
该文章在 2025/6/6 9:18:57 编辑过