boxmoe_header_banner_img

Hello! 欢迎来到我的博客!

加载中

文章导读

闭包


avatar
xiaoifei 2025年3月15日 68

闭包(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)

查看评论列表

暂无评论


发表评论

表情 颜文字
插入代码