02_閉鎖

グローバル変数

  1. すべてのグローバル変数を宣言し、すべてのウィンドウ属性//ウィンドウはグローバルドメインです
    eg: var a = 123; ==> window.a = 123;
  2. で、任意の変数、そうでない場合は代入文で、この変数はグローバル変数のすべてのことです:グローバル変数は、グローバル・ヒントを暗示します
    eg: function fn() { a = 321 } ==> window.a = 321;

プリコンパイル済み

機能を実行するプリコンパイルは前に起こりました:
  1. AOは、アクティベーションオブジェクト(コンテキストの実行)オブジェクトを作成します
  2. 変数の宣言と関数のパラメータを取得し、AOなどの可変パラメータ名と属性名は、定義されていません
  3. 引数とパラメータ団結
  4. 関数本体内の関数宣言、関数本体に割り当てられた値を探します
    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对象内部的变量赋值和访问
グローバルプリコンパイルされました:
  1. GOは、オブジェクトグローバルオブジェクト// GO ===ウィンドウを作成します
  2. GOのプロパティ値が定義されていないとして、変数宣言を探します
  3. 関数宣言、関数本体の値を探します

スコープ

[[scope]]:すべてのJavaScript関数はオブジェクト、私が訪問することができ、いくつかのプロパティの目的であるが、いくつかは、これらのプロパティは、JavaScriptエンジンにアクセスするためのものではありません、[[scope]]そのうちの一つです。
[[scope]]それは私たちが実施期間のコンテキストのセットを保存する範囲を、呼んでいるものを指し、

スコープチェーン:[[scope]]実行コンテキストオブジェクトのコレクションが格納され、このコレクションは、チェーンリンクだった、私たちはこのチェーンリンクはスコープチェーンと呼ばれる呼び出します。

コンテキストの実行:関数が実行されると、それは、コンテキストと呼ばれる内部オブジェクトの実装期間を作成します。コンテキストの実行は、実施期間の各実行コンテキストに対応する機能は、機能が終了したとき、機能は、複数の実行コンテキストの作成を引き起こすユニークなので、複数の呼び出しである場合関数は、実行される環境を定義し、それが生成します実行コンテキストが破棄されます。

  1. 関数が定義されている場合
    ここに画像を挿入説明
  2. 関数が実行されると、
    ここに画像を挿入説明
    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还在么?

あなたは、変数を見つけた場合、ダウン見つけるためにスコープチェーンの先頭から


クロージャ

    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是一直存在的么?(内存回收?)
  • この関数は、外部(リターン機能)に保存された内部関数です(関数は前の場合で機能することができ、まだアクセス環境変数、AO機能環境の前に返却する必要があるため)、クロージャが生成する必要があります。クロージャは、メモリリークが生じる、解放しない元のスコープチェーンにつながります。

  • パッケージは閉鎖されています。

    • パブリック変数を達成
      • 例:関数アキュムレータ
          function add() {
              var count = 0;
              function demo() {
                  count ++;
                  console.log(count);
              }
              return demo;
          }
      
          var counter = add();
      
          counter();  // 1
          counter();  // 2
          counter();  // 3
      
    • キャッシュを行うことができます(ストレージ構造)
      • 例:食べる人
          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();
      
    • パッケージには、プロパティの民営化を達成することができます
      • 例えば:人();
    • モジュラー開発、汚染を防止するためのグローバル変数

すぐに関数を実行

    (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);

閉鎖の問題を解決

    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

プログラムは、意味的に必要とする場合は、0-9印刷機能は、外部で行いました。クロージャを解決します:

    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>
リリース9件のオリジナルの記事 ウォンの賞賛0 ビュー1046

おすすめ

転載: blog.csdn.net/lochoto/article/details/104091765