关于JS中闭包剖析(包含闭包的理解、作用、生命周期、应用、缺点及其解决、常见的闭包)
发布日期:2021-05-12 21:17:48 浏览次数:21 分类:精选文章

本文共 3002 字,大约阅读时间需要 10 分钟。

JS中的闭包理解剖析

JS中的闭包抽象了函数与其周围环境之间的关系,避免了显式的环境传递,是函数嵌套编程的核心能力。以下从基础到应用,全面剖析JS中的闭包。

闭包的产生条件

闭包产生的前提条件是:

  • 函数嵌套。
  • 内部函数引用了外部函数的数据或函数。
  • 外部函数被调用。
  • 例如:

    function fn1() {    const a = 1;    function fn2() {        console.log(a);    };    return fn2;}function fn3() {    const b = 2;    fn2();}const f = fn1();f(); // 输出:1f(); // 输出:1

    闭包使得变量 a 存续存在,避免了局部变量的常规释放过程。

    常见闭包形式

    1. 函数返回一个函数

    function fnReturningClosure() {    let count = 0;    function fn() {        count++;        return count;    };    return fn;}const add = fnReturningClosure();add(); // 输出:1add(); // 输出:2

    返回新函数,形成闭包,其内部直接访问外部 count

    2. 传递函数作为参数

    function transmissionClosing() {    function innerFn() {        console.log('Inner');    };    return innerFn;}transmissionClosing()();

    当函数作为参数传递,内部函数在传递过程中形成闭包,确保能访问传递者的上下文。

    闭包的作用

  • 延长局部变量生命周期:避免局部变量的销毁,保证外部函数能够访问内部变量。
  • 封装访问权限:确保内部函数只能通过指定方式访问外部数据,防止外部随意修改。
  • 代码分析

    function fn1() {    const a = 1;    function fn2() {        console.log(a);    };    return fn2;}function fn3() {    const b = 2;    fn2();}const f = fn1();f(); // a 存在f = null; // 闭包释放f(); //无法调用,a 已经释放

    闭包生命周期

    闭包在预解析阶段创建,保持脚本执行期间存在。若不引用闭包,会在函数调用后自动释放。

    关键点

  • 预解析阶段:验证函数嵌套,确定闭包变量。
  • 闭包释放条件:闭包所在的变量被清理,或者手动释放。
  • 示例

  • 隐式创建闭包
  • function createClosure() {    const x = 'Closure Created!';    function inner() {        console.log(x);    };    return inner;}createClosure();
    1. 显式创建闭包
    2. function explicitClosure() {    const y = 'Explicitly Created!';    function inner() {        console.log(y);    };    return inner;}const closure = explicitClosure();closure();

      闭包应用

      模块化编程

    3. 封装功能
    4. function myModule() {    const msg = 'I Love SWPU';    function doSomething() {        console.log('doSomething() ' + msg.toUpperCase());    }    function doOtherthing() {        console.log('doOtherthing() ' + msg.toLowerCase());    }    return {        doSomething: doSomething,        doOtherthing: doOtherthing    };}window.myModule = myModule();
      1. 匿名函数实现
      2. (function() {    const msg = 'I Love SWPU';    function doSomething() {        console.log('doSomething() ' + msg.toUpperCase());    }    function doOtherthing() {        console.log('doOtherthing() ' + msg.toLowerCase());    }    window.myModule2 = {        doSomething: doSomething,        doOtherthing: doOtherthing    };})();

        优化技巧

        将闭包添加为 window 属性,避免每次加载重新创建,便于多次使用。

        (if (typeof window !== 'undefined') {(function(window) {    const msg = 'I Love SWPU';    function doSomething() {        console.log('doSomething() ' + msg.toUpperCase());    }    function doOtherthing() {        console.log('doOtherthing() ' + msg.toLowerCase());    }    window.myModule2 = {        doSomething: doSomething,        doOtherthing: doOtherthing    };})(window);})

        闭包的缺点及解决

        问题

        闭包导致内存泄漏,缺点在于长时间运行内存占用过高。

        解决方法

      3. 避免不必要的闭包:抵消闭包的形成条件。

      4. 及时释放闭包

      5. function fn() {    const arr = [];    for (let i = 0; i < 10; i++) {        arr.push({            key: i,            value: 'Closure Test'        });    }    function inner() {        console.log(arr);    };    inner();    // 处理完后释放    inner = null;}fn();

        总结:闭包在JS中扮演着至关重要的角色,理解其特性和使用方法,是提升代码质量和效率的关键。

    上一篇:关于JS中的内存溢出与内存泄漏
    下一篇:关于JS中的作用域链及其面试题

    发表评论

    最新留言

    表示我来过!
    [***.240.166.169]2025年04月22日 14时49分32秒