JavaScriptコアの実行コンテキスト、作用ドメインチェーン、クローズド

6222 ワード

実行コンテキストEC(Execution Contect)
  • 実行コンテキストは、1つの関数またはグローバルコードが実行される場合の環境であり、実行時に必要とされるデータを含み、オブジェクトとして理解できる.
  • 関数は、実行毎に新しい実行コンテキストを作成します.
  • 関数は、実行が終わるたびに、この実行コンテキストを破棄します.
  • 実行スタックCS(call stack)
  • 関数が実行されるたびに、実行コンテキストが新たに生成され、管理実行コンテキストのスタックが実行スタックである.
  • は、関数が実行されると、実行前に実行コンテキストを生成してスタックに組み込み、関数の実行が終了するとスタックが出てきます.
  • は、各実行中の関数がスタックトップのコンテキストで使用される.
  • スタックの底は常にグローバルコンテキストである.
  • 例を挙げます
    function foo() {
        console.log('foo     ');
    
        function bar() {
            console.log('bar     ');
        }
        
        bar();
    }
    
    foo();
    コード実行時、実行スタックはどのように変化しますか?
  • は、グローバルコンテキストG_ECを作成し、スタックに組み込む.
    実行スタック:
    G_EC
  • は、foo関数を実行し、fooの実行コンテキストfoo_ECを作成し、スタックに組み込む.
    実行スタック:
    foo_EC
    G_EC
  • console.log関数を実行し、console.log関数の実行コンテキストclg_ECを作成し、スタックに組み込む.
    実行スタック:
    グラムEC
    foo_EC
    G_EC
  • console.logの実行が完了し、「foo関数が実行されました」とプリントアウトし、clg_ECを廃棄し、スタックを出ます.
    実行スタック:
    foo_EC
    G_EC
  • bar関数を実行し、barの実行コンテキストbar_ECを作成し、スタックに組み込む.
    実行スタック:
    bar_EC
    foo_EC
    G_EC
  • console.log関数を実行し、console.log関数の実行コンテキストclg_ECを作成し、スタックに組み込む.
    実行スタック:
    グラムEC
    bar_EC
    foo_EC
    G_EC
    ここのclg_ECは全く新しい文脈で、前とは違って
  • です.
  • console.logの実行が完了し、「bar関数が実行されました」とプリントアウトし、clg_ECを廃棄し、スタックを出ます.
    実行スタック:
    bar_EC
    foo_EC
    G_EC
  • bar関数の実装が完了し、bar_ECを廃棄し、スタックを取り出す.
    実行スタック:
    foo_EC
    G_EC
  • foo関数の実装が完了し、foo_ECを廃棄し、スタックを取り出す.
    実行スタック:
    G_EC
  • すべてのコードが実行され、G_ECが破棄され、スタックが出ます.
    実行スタック:

  • コンテキストの内容を実行
    //            
    EC = {
        VO = {...},
        SC = [...],
        this = [...]
    }
    1.変数対象VO(Varebale Object)
  • は、関数が実行される前の瞬間に生産される.
  • はスタック上部のVOを実行し、実行対象AOとも呼ばれる.
  • は、スタックの底のVOを実行し、グローバルオブジェクトGO(Global Object)とも呼ばれる.
  • 2.作用ドメインチェーンSC(Scope Chin)
  • スコープチェーンは、コンテキストを実行するセットであり、各関数には「scope」属性があり、配列を指し、配列には自分の実行コンテキスト以外の実行コンテキストが保存されています.
  • 作用分域チェーンは、関数定義時に生成される.
  • 関数が変数を使用するときは、まず自分の実行文脈から検索します.見つけられない場合は、スコープに沿って上に探します.
  • 3.this
    コンテキストとしての実行の理解に影響しないでスキップします.thisの指向問題:
  • グローバル環境において、thiswindowオブジェクト
    console.log(this); //window
  • を指す.
  • 関数のthisは、window(厳格なモードでundefinedを指す)
    function foo(){
        console.log(this); //window
    }
    
    foo();
  • を指す.
  • callapplyを使用して呼び出され、thiscall/applyの第1のパラメータ
    var obj = {a: 1};
    
    function foo(){
        console.log(this); //obj
    }
    
    foo.call(obj);
    foo.apply(obj);
  • を指す.
  • は、オブジェクト内の関数を呼び出し、obj.funを用いて呼び出し、thisobj
    var obj = {
        a: 1,
        foo: function(){
            //obj.foo():this  obj,
            //bar():             ,this  window
            console.log(this);
        }
    };
    
    obj.foo();
    
    var bar = obj.foo;
    bar();
  • を指す.
    VOの作成過程
    一つの関数のVOを作成する時、jsエンジンがすること.
  • は、モダリティの値
  • を決定する.
  • 変数の宣言は
  • を上げます.
  • は、実参加の値を形参
  • に割り当てる.
  • 関数ステートメント全体のアップグレード
  • 同名の属性があると上書きされます.
    例を挙げます
    function foo(a, b){
        console.log(bar); //ƒ bar(){}
        console.log(a); //2
    
        function bar(){}
        
        var a = 1;
    }
    
    foo(2, 3);
    作成手順に従ってfoo関数のVO——foo_を生成します.VO
    //1.       ,          
    foo_VO = {
        arguments: {...}, //arguments      
        a: undefined,
        b: undefined,
    }
    
    //2.       ,          a,  VO     a  ,    
    foo_VO = {
        arguments: {...},
        a: undefined,
        b: undefined,
    }
    
    //3.          ,  foo(2, 3)      2, 3,     a, b
    foo_VO = {
        arguments: {...},
        a: 2,
        b: 3,
    }
    
    //4.       ,      foo, foo    VO   
    foo_VO = {
        arguments: {...},
        a: 2,
        b: 3,
        foo: function(){}
    }
    最後のfoo関数で発生したVOオブジェクトは
    foo_VO = {
        arguments: {...},
        a: 2,
        b: 3,
        foo: function(){}
    }
    VOの作成は関数実行前のものですので、関数は現在のVOで変数を検索できます.console.logは関数の一番前に置いても印刷できます.afooの値
    SCの内容
    SC=前の階層でコンテキストスタックを実行するAO+上の階層でコンテキストスタックのSCを実行します.
    例を挙げます
    function foo() {
        function bar() {
            function baz(){
                
            }
        }
    }
    グローバル実行コンテキストは、最初のSCが空です.
    g_EC = {
        SC: [],
        AO: {...},
        this: {...},
    }
    foo関数はコンテキストを実行します.ここで、SC=グローバルコンテキストのAO+グローバルコンテキストのSCです.
    foo_EC = {
        SC: [g_EC.AO], //[g_EC.AO, ...g_EC.SC]
        AO: {...},
        this: {...},
    }
    bar関数はコンテキストを実行し、SC=foo関数はコンテキストのAO+foo関数はコンテキストのSCを実行する.
    bar_EC = {
        SC: [foo_SC.AO, g_EC.AO], //[foo_SC.AO, ...foo_SC.SC],
        AO: {...},
        this: {...},
    }
    baz関数はコンテキストを実行し、SC=bar関数はコンテキストのAO+bar関数はコンテキストのSCを実行します.
    baz_EC = {
        SC: [bar_SC.AO, foo_SC.AO, g_EC.AO], //[bar_SC.AO, ...bar_SC.SC],
        AO: {...},
        this: {...},
    }
    関数を実行すると、変数を検索して、先に自分のAOを検索します.もしなかったら、SCの第0項、第1項に沿って順番に探してください.SCの最後の項目が見つからないとエラーが発生します.Uncaught ReferenceError: xxx is not defined包みを閉じる
    関数内のサブ関数が保存されると、その関数の外部には閉じられたパケットが形成されます.
    function foo(){
        var a = 1;
        return function bar(){
            return a;
        }
    }
    
    var baz = foo();
    var qux = baz();
    
    console.log(qux); //1
    fooは運転中です.
    foo_EC = {
        SC: [GO],
        AO: {
            a: 1,
            ...
        },
        this: {...},
    }
    fooが実行されたら、自分の実行文脈を破壊します.その中のAOも破壊されます.
    しかし、barは外部、つまりbazに保存されており、barの作用域SCにはfooのAOがあるので、これはなぜクローズドが形成されたのかを説明する.外部の関数は関数内部の変数を使用することができる.
    baz_EC = {
        SC: [foo_EC.AO, GO],
        AO: {...},
        this: {...},
    }
    何故ならbar関数は、グローバルスコープに保存されています.fooのAOはずっと存在していて、破壊されないので、メモリが漏れてしまいます.使用後は元のクローズドを外すべきです.baz = null閉塞の役割:
  • は、公有変数を実現する.
  • はキャッシュしてもいいです.
  • は、属性の私有化を実現する.
  • モジュール化し、グローバル変数の汚染を防止する.