📅  最后修改于: 2023-12-03 15:39:50.801000             🧑  作者: Mango
闭包是指函数在访问父级函数作用域变量时,形成的内部函数和该内部函数所在的环境的组合。简单来说,闭包可以让内部函数访问外部函数的作用域。
JavaScript中的函数是一等公民,因此可以将函数作为参数传递,也可以将函数作为返回值。当函数作为返回值时,就很容易形成闭包。
function outer() {
let count = 0;
function inner() {
count++;
console.log(count);
}
return inner;
}
let counter = outer();
counter(); // 1
counter(); // 2
上述代码中,outer
函数返回了inner
函数,由于inner
函数仍然可以访问outer
函数的作用域,因此count
变量在inner
函数中仍然可用。通过调用outer
函数返回的counter
函数,可以形成闭包,每次调用时count
都会自增1。
闭包可以让变量不被外界所访问,从而实现变量的封装。
function createCounter() {
let count = 0;
return {
increment: function() {
count++;
console.log(count);
},
reset: function() {
count = 0;
console.log(count);
}
}
}
let counter = createCounter();
counter.increment(); // 1
counter.increment(); // 2
counter.reset(); // 0
上述代码中,createCounter
函数返回了一个包含两个方法(increment
和reset
)的对象,这两个方法都可以访问count
变量,但是外界无法直接访问变量count
。
函数柯里化(Currying)是指将一个多参数的函数转换为一系列单参数的函数的技术,闭包可以很方便地实现函数柯里化。
function add(x) {
return function(y) {
return x + y;
}
}
let add5 = add(5);
console.log(add5(3)); // 8
上述代码中,add
函数返回了一个内部函数,内部函数利用闭包访问了外层函数的x
变量,从而可以实现对x
变量的记忆化,每次调用add
返回的内部函数时,都只需要传入一个参数y
即可得到结果。
防抖(Debounce)和节流(Throttle)是对事件频繁触发的一种优化方式,闭包可以很方便地实现防抖和节流。
防抖是指在某个时间段内,如果事件被触发多次,则只执行最后一次。
function debounce(fn, delay) {
let timeoutId;
return function() {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => {
fn.apply(this, arguments);
}, delay);
};
}
function handleInput() {
console.log('input事件被触发');
}
let debouncedInputHandler = debounce(handleInput, 300);
document.querySelector('input').addEventListener('input', debouncedInputHandler);
上述代码中,debounce
函数接受一个函数和一个时间间隔作为参数,返回一个函数,该函数在调用时利用闭包保存了timeoutId
变量,每当被触发时,都会清除之前的定时器,然后重新设置一个定时器,等待一定时间后再执行传入的函数。
节流是指在某个时间段内,只能触发一次事件。
function throttle(fn, delay) {
let prevTime = 0;
return function() {
let currTime = Date.now();
if (currTime - prevTime > delay) {
fn.apply(this, arguments);
prevTime = currTime;
}
};
}
function handleScroll() {
console.log('scroll事件被触发');
}
let throttledScrollHandler = throttle(handleScroll, 300);
document.addEventListener('scroll', throttledScrollHandler);
上述代码中,throttle
函数接受一个函数和一个时间间隔作为参数,返回一个函数,该函数在调用时利用闭包保存了prevTime
变量,每当被触发时,都会判断当前时间是否已经超过上一次执行事件的时间加上时间间隔,如果超过了则执行传入的函数,否则不执行。