闭包

Martin

定义在函数中的函数,使函数内部能访问到外部作用域的变量

表现形式:

1)、函数作为返回值被返回;

2)、函数作为参数被传入;

在定时器、事件监听、Ajax 请求、Web Workers 或者任何异步中,只要使用了回调函数,实际上就是在使用闭包

优点:封装私有变量(避免变量全局污染)、延长作用域变量。

1
2
3
4
5
6
7
8
9
// 数据封装(创建私有变量)
function createCounter() {
let count = 0; // 外部作用域的变量
return {
increment: () => ++count,
getCount: () => count
};
}
// count变量对外不可见,只能通过闭包方法访问
1
2
3
4
5
6
7
8
9
10
11
// 状态保持(记忆上下文)
function rememberMe() {
const cache = new Map();
return (key) => {
if (!cache.has(key)) {
cache.set(key, expensiveCalculation(key));
}
return cache.get(key);
};
}
// cache变量在多次调用间保持存活

缺点:使用不当可能造成内存泄漏

1
2
3
4
5
6
7
8
// 内存泄漏示例
function createHeavyObject() {
const bigData = new Array(1e6).fill("data");
return () => {
// 即使外部函数执行完毕,bigData仍被闭包引用无法回收
console.log(bigData.length);
};
}
1
2
3
4
5
6
7
8
// 性能问题示例
function createMultipleClosures() {
const data = "重要数据";
// 每次调用都会创建新的闭包作用域
return Array.from({length: 1000}, (_, i) => {
return () => console.log(data, i); // 创建1000个闭包
});
}

应用场景:函数的防抖和节流

⚠️注意:闭包和高阶函数和函数柯里化的特点

柯里化是一种将使用多个参数的函数转换成一系列使用一个参数的函数的技术;

高阶函数是指那些可以接受其他函数作为参数,或者返回一个函数的函数。常见于工厂函数和闭包中,本质上闭包函数也属于高阶函数。

https://segmentfault.com/a/1190000044158495