02_ closure

Global Variables

  1. Declare all global variables, all window attributes // window is the global domain
    eg: var a = 123; ==> window.a = 123;
  2. Global variables imply global hint: that is, any variable, if not on assignment statement, this variable is a global variable that all
    eg: function fn() { a = 321 } ==> window.a = 321;

Precompiled

Function performs pre-compiled happened before:
  1. AO create objects Activation Object (execution of context)
  2. Get variable declaration and the function parameter, the variable parameter name and attribute name as AO, is undefined
  3. The arguments and parameters unity
  4. Find a function declaration in the function body, the value assigned to the function body
    function fn (a, b) {
        console.log(a);  // function a () {}
        console.log(b);  // undefined
        var b = 234;
        console.log(b);  // 234
        a = 123;
        console.log(a);  // 123
        function a () {}
        var a;
        b = 234;
        var b = function () {}
        console.log(a);  // 123
        console.log(b);  // function b () {}
    }
    fn(1);  //先预编译,再执行

    // 预编译过程
    // 1. 创建AO
    AO = {}
    // 2. 找函数形参和变量声明,作为AO属性名,值为undefined
    AO = {
        a : undefined,
        b : undefined,
    }
    // 3. 将实参和形参统一
    AO = {
        a : 1,
        b : undefined,
    }
    // 4. 在函数体里面找函数声明,值赋予函数体
    AO = {
        a : function a () {},
        b : undefined,
    }

    //执行过程
    //对AO对象内部的变量赋值和访问
Global pre-compiled:
  1. GO create objects Global Object // GO === window
  2. Find variable declarations, as GO's property value is undefined
  3. Find a function declaration, the value of the function body

Scope

[[scope]]: Every JavaScript function is an object, the object of some property I can visit, but some do not, these properties are for accessing the JavaScript engine, [[scope]]is one of them.
[[scope]]It refers to what we call the scope, which stores the set of the context of the implementation period

Scope chain: [[scope]]a collection of execution context object is stored, this collection was chain link, we call this chain link is called the scope chain.

Execution of context: When the function is executed, it will create a context-called internal object implementation period. Execution of a context defines the environment when a function is executed, when the function corresponding to each execution context of the implementation period is unique, so multiple calls a function causes the creation of multiple execution context, when the function is finished, it generates the execution context is destroyed.

  1. When a function is defined
    Here Insert Picture Description
  2. When a function is executed
    Here Insert Picture Description
    function a() {}
    var glob = 100;
    a();

    // a函数被定义
    // a.[[scope]] --> 0: GO {}
    // a执行
    // a.[[scope]] --> 0: AO {}
    //                 1: GO {}

    function a() {
        function b() {
            var b = 234;
        }
        var a = 123;
        b();
    }
    var glob = 100;
    a();

    // a函数被定义
    // a.[[scope]] --> 0: GO {}
    // a执行
    // a.[[scope]] --> 0: a.AO {}
    //                 1: GO {}

    // b函数被定义
    // b.[[scope]] --> 0: a.AO {}
    //             --> 1: GO {}
    // b执行
    // b.[[scope]] --> 0: b.AO {}
    //             --> 1: a.AO {}
    //             --> 2: GO {}

    // 函数执行完后会删除AO,再次执行会生成新的AO。

    // 注意:当b执行完毕后,a才算执行完毕。
    // 问题:a和b执行完后是删除了[[scope]]里的所有还是只删除自己的AO?此时a把a.AO删除后,b还在么?

When you find variable, from the top of the scope chain in order to find down


Closure

    function a() {
        function b() {
            var bbb = 234;
            console.log(aaa);
        }
        var aaa = 123;
        return b;
    }

    var glob = 100;
    var demo = a();
    demo();  // 可以访问aaa, 打印123

    // 注意:此时b被返回,则a执行完毕,但是此时b未被执行过。

    // b定义但未执行时拥有a.AO,被return出去后,a就执行完毕,a执行完毕就删除对a.AO的引用。此时b仍拥有a.AO,即使b执行完毕只会删除b.AO,而不会删除a.AO的引用。

    // 问题:a.AO是一直存在的么?(内存回收?)
  • Function is an internal function saved to an external (return function), the closure must generate (because the function has to be returned before the AO function environment, in which case the function can still access environment variables before). Closure would lead to the original scope chain does not release, resulting in a memory leak.

  • Packages are closed:

    • Achieve public variable
      • eg: function Accumulator
          function add() {
              var count = 0;
              function demo() {
                  count ++;
                  console.log(count);
              }
              return demo;
          }
      
          var counter = add();
      
          counter();  // 1
          counter();  // 2
          counter();  // 3
      
    • Can do cache (storage structure)
      • eg: eater
          function test() {
              var num = 100;
              function a() {
                  num ++;
                  console.log(num);
              }
              function b() {
                  num --;
                  console.log(num);
              }
              return [a, b];
          }
      
          var myArr = test();
          myArr[0]();  // 101
          myArr[1]();  // 100
      
          function eater() {
              var food = "";
              var obj = {
                  eat: function() {
                      console.log("I am eating" + food);
                      food = "";
                  },
                  push: function(myFood) {
                      food = myFood;
                  }
              }
              return obj;
          }
      
          var eater1 = eater();
          eater1.push('banana');
          eater1.eat();
      
    • Package can be achieved, properties privatization
      • eg: Person();
    • Modular development, global variables to prevent contamination

Immediately execute the function

    (function test(){
        // to do ...
    } ())

    console.log(test);  // Uncaught ReferenceError: test is not defined
    // 两种写法
    (function () { ... }());  // W3C建议
    (function () { ... })();

    function test() {  // 函数声明
        console.log(1);
    }();  // Uncaught SyntaxError: Unexpected token ')'

    // 只有表达式才能被执行符号执行

    var test = function() {
        console.log(1);
    }();  // 1
    console.log(test);  // undefined
    // 被执行符号执行的函数表达式,会自动放弃函数。

    + function test() {  // 隐式转换为表达式(+ - ! && ||)
        console.log(1);
    }();  // 1
    console.log(test);  // Uncaught ReferenceError: test is not defined
    // 函数隐式转换为表达式后,会自动放弃函数

    (function test() {  // ()也让函数隐式转换为表达式
        console.log(1);
    })();  // 1
    console.log(test);  // Uncaught ReferenceError: test is not defined

    (function test() {  // ()也让函数隐式转换为表达式
        console.log(1);
    }());  // 1
    console.log(test);  // Uncaught ReferenceError: test is not defined

    // 因为函数被释放了,所以不取名
    function test(a, b, c, d) {
        console.log(a + b + c + d);
    }(1, 2, 3, 4);
    // 不会报错,浏览器识别为:
    function test(a, b, c, d) {
        console.log(a + b + c + d);
    }
    (1, 2, 3, 4);

Solve the problem of closure

    function test() {
        var arr = [];
        for(var i = 0; i < 10; i ++) {
            arr[i] = function () {  // 在执行test函数时,把函数体(的地址)赋给数组里每一位,数组里的i在循环的时候就立即改变。
                console.log(i);  // 只有当返回出去的数组内函数执行的时候,才去作用域链中找i的值
            }
        }
        return arr;
    }

    var myArr = test();  // test执行完,此时i已经为10
    for(var j = 0; j < 10; j ++) {
        myArr[j]();  // 此处返回出来的数组里的函数才开始执行,才去作用域链中找i的值。因为闭包,此处数组内函数访问的都是同一个i,切由于上一句test执行完i变为10。
    }
    // 打印十个10

If the program requires semantically, 0-9 printing functions performed by the external. Solve closure:

    function test() {
        var arr = [];
        for(var i = 0; i < 10; i ++) {
            (function (j) {
                arr[j] = function () {
                    console.log(j);  // 找的是对应立即执行函数里的j(即形参j),立即执行函数执行后会销毁,每一个立即执行函数的AO被保存到外部,每一个j不同。
                }
            }(i));
        }
        return arr;
    }

    var myArr = test();
    for(var j = 0; j < 10; j ++) {
        myArr[j]();
    }
    <ul>
        <li></li>
        <li></li>
        <li></li>
    </ul>

    <script>
        function test() {
            var liCollection = document.getElementsByTagName('li');

            for (var i = 0; i < liCollection.length; i ++) {
                liCollection[i].onclick = function () {  // 此类事件函数就将要执行的函数保存到外部了
                    console.log(i);
                }
            }
        }
        test();
    </script>
Released nine original articles · won praise 0 · Views 1046

Guess you like

Origin blog.csdn.net/lochoto/article/details/104091765