当前位置: 首页 > web >正文

闭包(Closure)及其作用和影响

一、闭包是什么

闭包(Closure)指的是​​一个函数能够记住并访问其词法作用域(lexical scope),即使该函数在其词法作用域之外执行​​。换句话说,闭包让函数可以“记住”它被创建时的环境。

闭包的核心特点​

  1. ​函数嵌套​​:闭包通常涉及嵌套函数(一个函数内部定义另一个函数)。
  2. ​内部函数引用外部变量​​:内部函数引用了外部函数的变量。
  3. ​外部函数执行完毕后​​:即使外部函数已经执行完毕,内部函数仍然可以访问外部函数的变量(因为这些变量被“保存”在内存中)。

示例

​解释​​:

  • outer() 执行后返回 inner 函数,并赋值给 counter
  • 即使 outer() 已经执行完毕,count 仍然存在于内存中(因为 inner 函数引用了它)。
  • 每次调用 counter() 时,count 都会递增,说明闭包“记住”了 count 的值。
  • 外部如果需要闭包的变量,则需要 return 。 如这里的 return inner;
function outer() {let count = 0; // 外部函数的变量function inner() {count++; // 内部函数引用外部变量console.log(count);}return inner; // 返回内部函数
}const counter = outer(); // outer() 执行完毕,但 count 仍然被保留
counter(); // 1(count 被记住)
counter(); // 2(count 继续累加)
counter(); // 3

    二、闭包的作用及使用场景

    1.数据私有化(封装私有变量)

    闭包可以创建私有变量,避免全局污染。

    ①普通形式

    外部可以访问到变量,不安全

    ②闭包形式

    function createCounter() {let count = 0; // 私有变量return {increment: function() { count++; },decrement: function() { count--; },getCount: function() { return count; }};
    }const counter = createCounter();
    counter.increment();
    console.log(counter.getCount()); // 1
    console.log(counter.count); // undefined(无法直接访问 count)

    2.函数工厂(动态生成函数)

    闭包可以用于创建具有特定行为的函数。

    适用场景​​:动态生成不同倍数的乘法函数、事件处理器等。

    function makeMultiplier(multiplier) {return function(num) {return num * multiplier;};
    }const double = makeMultiplier(2);
    const triple = makeMultiplier(3);console.log(double(5)); // 10
    console.log(triple(5)); // 15
    // 与函数柯里化相似

    3.事件监听、回调函数​

    闭包常用于异步编程(如事件监听、setTimeout),确保回调函数能访问外部变量。

    适用场景​​:事件绑定、AJAX 回调、Promise 链式调用等。

    function delayedGreeting(name) {setTimeout(function() {console.log(`Hello, ${name}!`);}, 1000);
    }delayedGreeting("Alice"); // 1秒后输出 "Hello, Alice!"

    4.防抖和节流

    闭包常用于实现防抖和节流,控制函数执行频率。

    适用场景​​:搜索框输入优化、滚动事件节流、按钮防重复点击。

    // 防抖:延迟执行,直到停止触发
    function debounce(fn, delay) {let timer;return function(...args) {clearTimeout(timer);timer = setTimeout(() => fn.apply(this, args), delay);};
    }window.addEventListener("resize", debounce(() => {console.log("Window resized!");
    }, 300));

    三、闭包的副作用

    1. 内存泄漏​

    闭包会长期持有外部变量,导致内存无法释放(如未清理的 DOM 引用)。

    function createHeavyClosure() {const largeData = new Array(1000000).fill("data");return function() {console.log(largeData.length); // 即使不再需要 largeData,它仍然被引用};
    }
    const closure = createHeavyClosure();
    // 如果不再需要 closure,但未手动解除引用,largeData 会一直占用内存

    2. this 绑定问题​

    闭包中的 this 可能指向全局对象(非严格模式)或 undefined(严格模式)。

    const obj = {name: "Alice",getName: function() {return function() {console.log(this.name); // 错误!this 指向全局对象(非严格模式)};}
    };
    obj.getName()(); // undefined

    3. 性能影响​

    闭包会增加内存消耗,因为外部函数的变量不会被垃圾回收(GC),直到闭包不再被引用。

    四、副作用解决办法(处理闭包带来的内存泄漏问题

    1. 手动解除引用​

    如果闭包不再需要,手动将其置为 null,让垃圾回收器回收内存。

    let closure = (function() {let largeData = new Array(1000000).fill("data");return function() {console.log(largeData.length);};
    })();closure(); // 使用闭包
    closure = null; // 手动解除引用,释放内存

    2. 避免不必要的闭包​

    在不需要闭包的场景,尽量使用普通函数。

    // 不推荐(闭包)
    function createClosure() {let data = "some data";return function() { console.log(data); };
    }// 推荐(直接返回数据)
    function getData() {return "some data";
    }

    3.注意事件监听的清理​

    在组件销毁时,移除事件监听器

    function setupEvent() {const button = document.querySelector("button");function handleClick() {console.log("Clicked!");}button.addEventListener("click", handleClick);// 在不需要时移除监听return () => button.removeEventListener("click", handleClick);
    }const cleanup = setupEvent();
    // 当不再需要时调用 cleanup()
    cleanup();

    4.使用现代框架的优化机制​

    • ​React​​:在组件卸载时清理 useEffect 的副作用。
    • ​Vue​​:在 beforeUnmount 钩子中清理事件监听。
    • ​Node.js​​:使用 WeakRef 或手动清理定时器/事件。
    http://www.xdnf.cn/news/3729.html

    相关文章:

  • 《ATPL地面培训教材13:飞行原理》——第5章:升力
  • 【算法应用】基于灰狼算法优化深度信念网络回归预测(GWO-DBN)
  • C# 运算符重载深度解析:从基础到高阶实践
  • MIT6.S081-lab8
  • 十一岁少年叶珉雪用艺术点亮公益之路 个人原创公益演唱会传递大爱与担当
  • C++类_构造函数
  • DBSCAN对比K-means
  • 软件第三方测试报告:从测试背景目的到方法范围全解析?
  • 域名与官网的迷思:数字身份认证的全球困境与实践解方-优雅草卓伊凡
  • Java 网络安全新技术:构建面向未来的防御体系
  • 【三班网】初中最后一次研学活动纪实
  • 如何提升个人的理解能力?
  • 生成式 AI 的优势
  • 软件管理(安装方式)
  • 【关于LM311实现过零比较器输出波形】2022-9-27
  • 【自然语言处理与大模型】使用Xtuner进行模型合并与导出
  • NHANES指标推荐:triglyceride levels
  • MySQL安装完全指南:从零开始到配置优化(附避坑指南)
  • java_Lambda表达式
  • C++函数详解:从基础到高级应用
  • 二维码批量识别—混乱多张二维码识别-物品分拣—-未来之窗-仙盟创梦IDE
  • 生成式 AI 的阐释
  • 解决Maven项目中报错“java不支持版本6即更高的版本 7”
  • 使用python加edge-tts实现文字转语音
  • AI 采用金字塔(Sohn‘s AI Adoption Pyramid)
  • 《TensorFlow 与 TensorFlow Lite:协同驱动 AI 应用全景》
  • string的两种实现
  • 华为云Astro轻应用自定义连接器对接OBS云对象存储操作指南
  • No qualifying bean of type ‘XXX‘ available
  • AVInputFormat 再分析