js之到底什么是闭包?

155 阅读2分钟

「这是我参与2022首次更文挑战的第15天,活动详情查看:2022首次更文挑战

前言

前端面试三大内容,作用域、闭包、原型链,可想而知闭包的重要程度,但是讲实话通过我工作的经验来看闭包在项目中使用的真的不算多,也可能是我做的项目太简单了,也可能是我根本不了解闭包,因此用的比较少。但闭包真的很重要,起码对面试来说,所以不管因为什么都要把闭包给学明白了。

什么是闭包

到底什么是闭包呢?

闭包其实就是指那些可以访问自由变量的函数(自由变量就是既不是函数的参数也不是函数的局部变量的变量)

上面的闭包定义是理论上的定义,实际的定义必须满足以下两点

  • 当创建它的上下文已经销毁了但是它仍然存在
  • 它可以访问自由变量 只有满足了上面两点才是实际意义上的闭包

例子

    var arr = [];

    for (var i = 0; i < 3; i++) {
      arr[i] = function () {
        console.log(i);
      };
    }

    arr[0]();
    arr[1]();
    arr[2]();

上面代码在面试中经常被问到,上面的三个输出结果都是3,但其实我们想要的是输出0,1,2,要怎么改才能实现输出的结果是0,1,2呢,如下代码

     var arr = [];

    for (let i = 0; i < 3; i++) { //这里我们只需要把var改成let即可
      arr[i] = function () {
        console.log(i);
      };
    }

    arr[0]();
    arr[1]();
    arr[2]();
    

同样,除了上面的var改成let关键字,还可以利用闭包的特性,也就是上下文已经销毁了但它依然存在,并且可以使用父函数的变量(也就是自由变量),代码如下

  var arr = [];

    for (let i = 0; i < 3; i++) { //这里我们只需要把var改成let即可
      arr[i] = (function (i) {
          return function(){
              console.log(i)
          }
      })(i);
    }

    arr[0]();
    arr[1]();
    arr[2]();

更容易记忆的闭包的定义(实际应用中)

  • 函数里边嵌套的子函数
  • 子函数调用父函数的局部变量(也可以叫做私有变量)
  • 通过return将子函数暴露在全局变量 这个子函数就是闭包
    var a=1;
    function fun(){
        var a=2;
        return function(){
            a++;
            console.log(a);
        }
    }
    var fun1 = fun();
    fun1();//3

闭包的优缺点

优点

  1. 可以让局部变量长期保存在内存中

  2. 避免污染全局变量

  3. 可以读取父函数的局部变量 缺点

  4. 如果乱使用闭包可能会造成内存泄露,并且由于函数的嵌套会影响性能

  5. 由于闭包被return到了父函数外部,可能出现改变父函数内部变量的情况