JavaScript 中闭包问题详解

124 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第 9 天,点击查看活动详情

闭包的概念

指有权访问另一个函数作用域中的变量的函数,一般情况就是在一个函数中包含另一 个函数。

闭包的作用

访问函数内部变量、保持函数在环境中一直存在,不会被垃圾回收机制处理; 简单地说:就是在函数的局部范围内声明一个封闭的环境,此环境不会被垃圾回收探测到。保证了数据 的安全唯一性

想了解闭包,首先要了解什么是全局变量,什么是局部变量

局部变量

a 是一个局部变量。局部变量只能用于定义它函数内部。对于其他的函数或脚本代码是不可用的。

函数可以访问由函数内部定义的变量。

    function sum(){
        var a=4;
        return a*a;
    }
    console.log(sum())
    console.log("输出:"+a);

image.png

全局变量

a 是一个全局变量。在web页面中全局变量属于 window 对象。全局变量可应用于页面上的所有脚本。

函数也可以访问函数外部定义的变量。

    b=4;
    function sum(){
        c=5;
        var a=4;
        return a+b+c;
    }
    console.log(sum())
    
    console.log("输出:"+b);
    console.log("输出:"+c);
    console.log("输出:"+a);

image.png

  • 全局和局部变量即便名称相同,它们也是两个不同的变量。修改其中一个,不会影响另一个的值。

  • 不适用var声明的变量,就是全局变量

  • 用 var声明,并且在函数的内部。这样的变量叫做局部变量,有效范围只能在其声明的函数内部。

  • 全局变量的作用域是全局性的,即在整个JavaScript程序中,全局变量处处都在。而在函数内部声明的变量,只在函数内部起作用。这些变量是局部变量,作用域是局部性的;函数的参数也是局部性的,只在函数内部起作用。

需求:设想下如果你想统计一些数值,且该计数器在所有函数中都是可用的。

    count=0;
    function add(){
        count++;
    }
    add();
    add();
    add();
    console.log(count);

image.png

计数器数值在执行 add() 函数时发生变化。但问题来了,页面上的任何脚本都能改变计数器,即便没有调用 add() 函数。

谁都可以访问 count,所以 count 变量并不安全,因为是全局变量。

如何才能安全呢?将 count声明为局部变量.

function add(){
        var count=0;
        return count++;
    }
    add();
    add();
    add();

    console.log(add());

image.png

本意是想输出 3, 但事与愿违,输出的都是 0 !

所有函数都能访问全局变量。实际上,在 JavaScript 中,所有函数都能访问它们上一层的作用域。JavaScript 支持嵌套函数。嵌套函数可以访问上一层的函数变量。

    function add(){
        var count = 0; //局部变量
        function jia(){
            return count++;
        }
        jia();
        return count;
    }
    add();
    add();
    add();

    console.log(add());

如果每次只调用 add()里面的 jia()就好了。ok,闭包帮你解决此问题!

image.png

自我调用

   var add = (function () {
    var counter = 0;
    return function () {
            return counter += 1;
            }
    })();
    add();
    add();
    add();

    console.log(add());

变量 add 指定了函数自我调用的返回字值。自我调用函数只执行一次。设置计数器为 0。并返回函数表达式。add变量可以作为一个函数使用。非常棒的部分是它可以访问函数上一层作用域的计数器。这个叫作 JavaScript 闭包。 它使得函数拥有私有变量变成可能。计数器受匿名函数的作用域保护,只能通过 add 方法修改。

闭包是一种保护私有变量的机制,在函数执行时形成私有的作用域,保护里面的私有变量不 受外界干扰。直观的说就是形成一个不销毁的栈环境。

  • 闭包的优点: 方便调用上下文中声明的局部变量 逻辑紧密,可以在一个函数中再创建个函数,避免了传参的问题
  • 闭包的缺点: 因为使用闭包,可以使函数在执行完后不被销毁,保留在内存中,如果大量使用闭包就会造 成内存泄露,内存消耗很大