函数闭包的理解

  1. 函数本身也是一个值,也有自己的作用域。它的作用域与变量一样,就是其声明时所在的作用域,与其运行时所在的作用域无关。(与this不一样)

    var a = 1111;
    var x = function () {
      console.log(a);
    };
    
    function f() {
      var a = 2222;
      x();
    }
    
    f() // 1111
    
    • 函数x是在函数f的外部声明的,所以它的作用域绑定外层,内部变量a不会到函数f体内取值,所以输出1111,而不是2222。
    • 总之,函数执行时所在的作用域,是定义时的作用域,而不是调用时所在的作用域。
  2. 闭包

    function f1() {
      var n = 123;
    }
    
    console.log(n)
    // Uncaught ReferenceError: n is not defined
    // 函数f1内部声明的变量n,函数外是无法读取的。
    
    • 正常情况下,这是办不到的,只有通过变通方法才能实现。那就是在函数的内部,再定义一个函数。

      function f1() {
       var n = 123;
       function f2() {
           console.log(n); // 123
        }
      }
      
      • JavaScript语言特有的”链式作用域”结构(chain scope),子对象会一级一级地向上寻找所有父对象的变量。所以,父对象的所有变量,对子对象都是可见的,反之则不成立。
    • f2可以读取f1的局部变量,那么只要把f2作为返回值,在f1的外部读取f1定义变量的值

      ```js
      function f1() {
          var n = 123;
          function f2() {
          console.log(n);
        }
        return f2;
      }
      
      var result = f1();
      result(); // 123
      ```
      
    • 闭包最大的特点,就是它可以“记住”诞生的环境,比如f2记住了它诞生的环境f1,所以从f2可以得到f1的内部变量。在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。

  3. 闭包和私有数据

    const uniqueId = (function() {
        let count = 0;
        return function() {
            ++count;
            return id_${count};
        };
    })();
    
    console.log(uniqueId()); // "id_1"
    console.log(uniqueId()); // "id_2"
    console.log(uniqueId()); // "id_3"
    

    在IIEF之外无法访问这个计数变量count。除了从IIEF中返回的函数,别人无法读写该变量。这样就能创建真正的私有状态,它只能以受控的方式进行修改。

    const counter = (function() {
        let counterValue = 0;  
    
        return {
            increment() {
                ++counterValue;  
            },  
    
           get value() {
                return counterValue;
            }
        };
    })();
    
    counter.increment();
    console.log(counter.value); // 1
    
    counter.increment();
    counter.increment();
    console.log(counter.value); // 3
    

你可能感兴趣的:(函数闭包的理解)