闭包(closure)是一个函数与其词法环境(lexical environment)的组合,允许函数“记住”并访问其定义时的作用域,即使该函数在其原始作用域外执行。
其表现形式为闭包=内层函数+外层函数的变量
闭包保证了对外部变量的持续引用从而使得不会被GC所回收,达到了拓展外部变量生命期的作用。同时运用封装函数执行时形成私有的作用域,保护里面的私有变量不受外界干扰。
function outer(){
let i = 1;
return function(){
console.log(i);
};
};
//调用
const func = outer();
func();
inner 函数在 outer 内部定义,可以访问 i。即使 outer() 执行完成后,inner 仍然保留对 i 的引用。
闭包的作用:
1. 实现私有变量,避免全局污染
2. 函数工厂
3. 事件处理回调
这里举几个例子详细说明
一、计数器
function createCounter() {
let count = 0;
return {
increment: () => { count++; },
getCount: () => count,
};
}
const counter = createCounter();
counter.increment();
console.log(counter.getCount()); // 输出 1
外部无法直接访问 count,从而实现了内部私有变量的保护
二、函数工厂
function multiplyBy(n) {
return (x) => x * n;
}
const double = multiplyBy(2);
console.log(double(5)); // 输出 10
这个有点类似于简单的工厂模式,封装创建逻辑,按需生产特定实例
三、事件处理与回调
function handleClick(message) {
return () => {
console.log(message); // 闭包保留 message 的值
};
}
const button = document.querySelector('button');
button.addEventListener('click', handleClick('Button clicked!'));
闭包的副作用:
由于闭包有引用外部函数变量的特点,因此会导致变量无法被释放而造成内存的泄露,所以我们需要谨慎地使用闭包
防抖与节流
防抖:
function debounce(fn, delay) {
let timer; // 这个变量被闭包“记住”,不会被销毁
return function (...args) {
if (timer) clearTimeout(timer); // 清除之前的定时器
timer = setTimeout(() => {
fn.apply(this, args); // 在 delay 时间后执行 fn
}, delay);
};
}
// 使用示例
const handleInput = debounce(() => {
console.log("搜索请求发送");
}, 500);
document.getElementById("search").addEventListener("input", handleInput);
节流:
function throttle(func, limit) {
let timer; // 通过闭包保存定时器状态
return function(...args) {
if (!timer) {
timer = setTimeout(() => {
func.apply(this, args);
timer = null; // 清除定时器状态
}, limit);
}
};
}
const log = throttle(() => {
console.log("触发滚动事件");
}, 1000);
window.addEventListener("scroll", log);
评论(0)
暂无评论