总结于bi站up 前端小夏老师

众说闭包 闭包是什么?

  1. 犀牛书:函数变量可以保存在函数作用域内,从技术角度讲,所有函数都是闭包

    function bar(){
        let n = 0;
    }
  2. 高级程序设计:闭包是指有权访问另一个函数作用域中变量的函数(函数没导出)

    function foo(){
        let n = 0;
        function bar(){
           console.log(n)
       };    
       bar();   //bar就是闭包
    }
    foo()
  3. 你不造的js: 当函数可以记住并访问所在的词法作用城时,就产生了闭包,即使函数是在当前词法作用域之外执行。

    function  foo(){
        let n = 0;
        return function bar(){   //bar就是闭包
            console.log(n);
        };
    }
    foo()();
  4. MDN:一个函数和对其周围状态(词法环境)的引用捆绑在一起(或者说函数被引用包围),这样的组合就叫闭包。也就是说,闭包让你可以在一个内层函数中访问到其外层函数的作用域。在JavaScript 中,每当创建一个函数,闭包就会在函数创建的同时被创建出来。

总结 参考常见形式便于理解

  1. 函数的执行,导致函数被定义(被定义的函数可以拿到父函数的变量)

  2. 闭包和函数的定义有关

  3. this和函数的执行方式有关

不是闭包的例子:

function foo(fn){
    let n = 0;
    fun();
}
function text(){
    console.log(n);
}
foo(test);

闭包常见形式:

  1. 函数的返回值是函数

     function foo(){
         let n = function(){
    
         }
         return n;
         //or
         //return function(){};
     }
  2. 函数内全局定义函数

      let func;
      function foo(){
          let n = 1;
          func = function(){console.log(n)};
      }
  3. 函数参数

      let func = function(fn){
          console.log(fn())
      };
      function foo(){
          let a = 'aaa';
          let n = function(){return a};
          func(n)
      }
      foo();
      //------------------------------------------------------------
      (function(){
          let a = 'aaa';
          let n = function(){return a};
          func(n)
      })()
  4. 循环赋值

      function foo(){
          let arr = [];
          for(var i =0; i<10; i++){
              arr[i] = function(){
                  console.log(i);   
              }
          }
          return arr;
      }
      let bar = foo();
      bar[0]()    //10
      //不用let从零打印:
      function foo(){
          let arr = [];
          for(var i =0; i<10; i++){
              arr[i] = (function(j){xx
                  console.log(j);   
              }
          })(i)
          return arr;
      }
      let bar = foo();
      bar[0]()    //0