27.闭包Closure

88 阅读2分钟

闭包是什么

首先闭包他不是一个具体的东西,而是由于js代码执行时形成的一种现象.简单来说就是:闭包就是能够读取其他函数内部变量的函数

闭包详解

我们在函数内部定义了一个变量 let a = 1; 正常情况我们在函数外部是访问不到这个变量的 ,因为函数内部会形成一个局部作用域,当我们在外部访问时就回报错改变量未定义.

      function foo() {
        let a = 0;
      }
      console.log(a);// a is not defined

有一个需求,如果我们需要获取到这个变量的值怎么办呢,我们可以return这个值

  function foo() {
    let a = 1;
    return a;
  }
  console.log(foo()); //1

我们获取到了 这个值,但是现在新增需求了,我们又需要修改他怎么呢,我们可以用一个变量来接这个变量,然后修改

      function foo() {
        let a = 1;
        return a;
      }
      let b = foo();
      b += 1;
      console.log(b);

image.png 我们可以看到b成功接到a的值,而且得到了+1的值,但是又一个问题就是,函数内部的值并没有改变,所以我们需要在函数foo内部操作,才能改变 变量a的的值

      function foo() {
        let a = 1;
        return function () {
          a += 1;
          return a;
        };
      }
      console.log(foo()()); // 2
      console.log(foo()()); // 2

我们可以发现我们一家成功修改了a的值,而且2次修改都是独立完成的.以上 我们就简单的完成了一个闭包.

闭包的使用

封装私有变量

      function f1() {
        var sum = 0;
        var obj = {
          inc: function () {
            sum++;
            return sum;
          }
        };
        return obj;
      }
      let result1 = f1();
      let result2 = f1();
      console.log(result1.inc(), result1.inc()); // 1 2
      console.log(result2.inc(), result2.inc()); // 1 2

可以看到我们封装了一个函数f1,返回了一个对象obj,对象中有一个方法inc,内部num++,然后返回num. 然后用result1和result2去接f1的返回值这个对象.可以发现result1,result2是独立的2个num值

防抖

function debounce(fn,delay){ let timer = null //借助闭包 return function() { if(timer){ clearTimeout(timer) timer = setTimeOut(fn,delay) }else{ timer = setTimeOut(fn,delay) } } } 我们常用的防抖函数,这个定时器timer就是一个闭包的变量

弊端

  • 由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。
  • 闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。