jsのプリコンパイル、スコープチェーン


プリコンパイル
1.jsコードの実行手順
  • 文法解析:主にコードをスキャンしますが、文法上の誤りがありますか?例えば、括弧が少ない、中国語の記号を書きました.
  • プリコンパイル:変数の宣言アップグレードを行い、関数全体を向上させ、直前の準備を行う.
  • 解釈実行:jsコードを実行し、行を解釈し、行を実行する.
  • 2.プリコンパイルの前奏
  • は、大域変数を意味します.宣言なしに値が割り当てられ、この変数は大域的に所有されます.
  • すべてのグローバル変数はwindowの属性
  • です.
    たとえば:
    var a = 100;
    console.log(window.a); //100
    if(1){
        a = 10;
    }
    console.log(window.a); //10
    
    3.プリコンパイル
    スクリプトコードブロックスクリプトが実行される前に、システムが実行する操作
  • は、GOオブジェクトを作成します.つまり、windowグローバルオブジェクト
  • です.
  • は、グローバル変数宣言(暗黙的大域変数宣言を含み、var宣言を省略する)を検索し、変数名作のグローバルオブジェクトの属性、値はundefined
  • である.
  • 関数宣言を検索します.関数名は大域オブジェクトの属性として、値は関数参照
  • です.
    例えば
    console.log(a);     //undefined
    console.log(func);  //func
    var a = 100;
    function func(){
        return 1;
    }
    
    関数実行前の操作
  • は、AOオブジェクト(実行期間コンテキスト)
  • を作成する.
  • は、関数内のモダリティを発見し、変数宣言はAOの属性名として、undefined
  • とする.
  • は、実参加と形参を統一する
  • .
  • は、定義された関数名をAOの属性に付け、値は関数体とする.
  • 面接の問題を見に来ました.
    a = 100;
    function demo(e){
        function e(){}
        arguments[0] = 2;
        console.log(e);
        if(a){
            var b = 123;
            function c(){}
        }
        var c;
        a = 10;
        var a;
        console.log(b);
        f = 123;
        console.log(c);
        console.log(a);
    }
    var a;
    demo(1);
    console.log(a);
    console.log(f);
    
    予編訳を使ってこの問題を分析してみます.
    1,      GO  
    GO = {}
    2,       ,  62,46    ,   
    G0 = {
        a:undefined,
        demo:function(){...}
    }
    3,      ,  45    ,   
    GO = {
        a:100,
        demo:function(){...}
    }
    4,63     ,         
    AO={}
    5,         ,      AO    ,  undefined
    AO={
        e:undefined,
        d:undefined,   
        c:undefined,    
        d:undefined,    
    }
    6,      
    AO={
        e:1,
        d:undefined,    
        c:undefined,    
        d:undefined,   
    }
    7,         AO    ,     
    AO={
        e:function(){...},
        d:undefined,    
        c:undefined,    //  if,       
        d:undefined,    
    }
    8,    
    function demo(e){
        function e(){}
        arguments[0] = 2;       //   AO ,  AO e 2
        console.log(e);         //2
        if(a){                  //  if
            var b = 123;
            function c(){}
        }
        var c;
        a = 10;                 //   AO ,  AO a 10
        var a;
        console.log(b);         //   ,undefined
        f = 123;                //   var, GO  
        console.log(c);         //     ,undefined
        console.log(a);         //10
    }
    var a;
    demo(1);
    console.log(a);             //  GO  a  
    console.log(f);             //  GO   f  
    
    最後の結果
    2
    undefined
    undefined
    10
    100
    123
    
    スコープ
    1.グローバルスコープ
    JSにはグローバルオブジェクトがあります.windowでは、グローバル宣言の変数はすべてwindowの属性に属します.
    var a = 10;
    b = 10;
    function fun(){
        c = 10;
        var d = 10;
    }
    fun();
    console.log("window.a",window.a);   //10
    console.log("window.b",window.b);   //10
    console.log("window.c",window.c);   //10
    console.log("window.d",window.d);   //undefined
    
    2.作用ドメインチェーン
    関数を定義するとき、関数はデフォルトでscopeという暗黙的な属性が存在します.すなわちドメインは、この属性は配列を指します.配列中に存在するのはチェーン式の関数セットがコンテキストを実行します.関数が定義されている時には、直接に親モジュールの役割領域を持ちます.例えば、windowで定義されている関数は、直接windowの役割領域を持ちます.関数が実行されると、独自の実行期間コンテキストが生成されます.
    この例です
    var a=10
    //    window{
    //	a:10
    //}
    function fun1(){
    	var b=20;
    	function fun2(){
    	    //
    	}
    	fun2();
    }
    fun1();
    
    上述のように、プリコンパイルとスコープによってコード運行の具体的な手順を解読します.
    1.  ,       GO, window  
    2.    fun1 ,   window    , scope     ,      ,     GO,
     scope(fun1):GO -->
    2    fun1 ,       fun1        AO,  scope      AO  ,
     scope(fun1):AO(fun1) --> GO -->
    3.    fun1 , fun1    ,       fun2,    fun2 scope  ,     fun1,
     scope(fun2): AO(fun1) --> GO -->
    4.       fun2 ,        fun2      ,  ,fun2 scope      ,
     scope(fun2): AO(fun2) --> AO(fun1) --> GO -->
    5,     fun2 ,      
    6,     fun1 ,      
    
    アクセス変数の順番を見てください.
    var cc = 123;
    function a(){
        function b(){
            var bb = 234;
            aa = 0;
            console.log(cc);
        }
        var aa = 123;
        var cc = 111;
        b();
        console.log(aa);       
    }
    a();
    
    
    今関数bで変数にアクセスすると、関数bのscopeの中にシステムが探しに行きます.scopeは1つの配列です.0番目からアクセスします.1番目は関数bの作用領域です.見つけられないなら、関数aの作用領域を探し続けます.見つけられないなら、windowの作用領域で探し続けます.最後に見つけられない変数を探してください.間違ったことを投げることがあります.関数の実行結果は
    111
    0
    
    包みを閉じる
    内部関数を外部に保存すると、クローズドが生成されます.クローズドが生成された後も、内部関数は外部関数の変数にアクセスできます.
    原理
    内部関数が定義されているときに内部関数に属するscope属性がスコープチェーンを保存しています.これは直接親関数のスコープチェーンを継承します.これは親関数に対する変数のアクセスがあるときに、このスコープは親レベル関数が破壊されないので、内部関数は親レベル関数の変数にアクセスできます.これはクローズドです.
    解決方法
    直ちに関数、letを実行します.
    例えば
    クローズドを使ってカウンタを実現します.
    function counterCreate(){
        var count = 0;
        return function(){
            count++;
            console.log(`  ${count} `);
        }
    }
    var addCount = counterCreate(); //        
    addCount();//  1 
    addCount();//  2 
    addCount();//  3 
    addCount();//  4 
    
    クローズドを使ってループ印刷を行います.
    for (var i = 0; i < 5; i++) {
      setTimeout(function timer() {
        console.log(i);
      }, i * 100);
    }
    //  5 5 5 5 5 
    
    即時実行関数を使う
    for (var i = 0; i < 5; i++) {
        (function (i) {
        setTimeout(function timer() {
          console.log(i);
        }, i * 100);
        })(i);
    }
    //   0 1 2 3 4
    
    クローズドのメリット
  • は、1つの変数が長くメモリに記憶されることを望む
  • .
  • グローバル変数の汚染を避ける
  • プライベートメンバの存在
  • はキャッシュ
  • のために使用されます.
    クローズドのデメリット
    メモリ漏れの原因になりやすい