闭包
在javascript中变量的存在是有生命周期的,函数里面的变量当函数执行完成后就会被销毁,但是通过闭包可以延长变量的生命周期。 闭包是在函数内部使用了外部作用域中的变量,使得该变量无法被正常销毁。闭包形成了一个封闭的持续存在的作用域,具有封闭和持续的特性,闭包的功能非常强大,例如单例模式、防抖、节流、柯理化、模块化等。
最简单的闭包代码
function outer() {
let count = 0;
return function inner() {
console.log(++count);
}
}
const func = outer();
func(); // 1
func(); // 2
闭包的应用场景
- 单例模式(Singleton)
单例模式应用于全局只需要一个实例的场景,例如全局的loading,全局的弹窗等,具有节省代码、方便统一管理的优点。
function Singleton() {
let instance;
function createInstance(name) {
this.name = name;
this.sayName = function() {
console.log(this.name);
}
}
return function(name){
if(!instance){
return instance = new createInstance(name);
}else{
return instance;
}
}
}
const createSingleton = Singleton();
const obj1 = createSingleton('obj1');
const obj2 = createSingleton('obj2');
obj1.sayName(); // obj1
obj2.sayName(); // obj1
- 防抖函数(Debounce)
防抖函数是指事件在n秒内只能触发一次,n秒内再次触发事件会重新计时,常用于减少表单提交次数、减少搜索框实时搜索调用接口的次数。
function debounce(func, dealy) {
let timerId;
return function () {
if (timerId) {
clearTimeout(timerId);
timerId = null;
} else {
timerId = setTimeout(() => {
func.apply(this, arguments);
}, delay);
}
};
}
- 节流函数(Throttle)
节流函数是每隔n秒事件执行一次,目的是降低事件执行的频率,比如鼠标移动事件、窗口resize事件等。
function throttle(func, delay) {
let timerId;
return function () {
if (!timerId) {
timerId = setTimeout(() => {
func.apply(this, arguments);
clearTimeout(timerId);
timerId = null;
}, delay);
}
};
}
- 函数柯理化(Currying)
函数柯理化可以将一个接收到个参数的函数,转换为多个接收一个参数的函数,可以提高函数的复用。
function curry(fn) {
return function curried() {
return fn.apply(this, arguments);
};
}
const add = curry(function (a, b) {
return a + b;
});
- 模块化(Module)
闭包可以将过程封装到函数内部,只暴露必要的接口。
// 闭包模块化
function module() {
let count = 0;
function add(x) {
return (count += x);
}
function subtract(x) {
return (count -= x);
}
function getCount() {
return count;
}
return {
add,
subtract,
getCount,
};
}
闭包的缺点
不是所有的闭包都会造成内存泄漏,内存泄漏是指没被使用的变量没有被销毁,因此当不再使用闭包的时候要注意清理引用。
function counter() {
let count = 0;
return function () {
return ++count;
};
}
const addCount = counter();
console.log(addCount()); // 1
console.log(addCount()); // 2
addCount = null; // 清理闭包引用