『君が知らないJavaScript(上)-役割ドメインとクローズドパッケージ』学習ノート

4128 ワード

1.コンパイル原理:


(1)コンパイラ、役割ドメイン、エンジン
  • コンパイラは、繰り返し宣言
  • を無視します.
  • コンパイル原理(p 7):
  • たとえば、var a=2では、コンパイラは次の処理を行います.
  • 1.var aに遭遇すると、コンパイラは、同じ役割ドメインのセットにすでに名前の変数が存在するかどうかを尋ねます.もしそうであれば、コンパイラは宣言を無視してコンパイルを続行します.それ以外の場合、現在の役割ドメインのセットに新しい変数を宣言し、aと命名する必要があります.
  • 2.次に、コンパイラは、a=2という付与操作を処理するために使用されるエンジンの実行に必要なコードを生成する.エンジンが実行されると、まず、現在の役割ドメインセットにaという変数が存在するかどうかを役割ドメインに尋ねます.もしそうなら、エンジンはこの変数を使用します.そうでない場合、エンジンは、変数が見つかるまで、または最外層の役割ドメイン(つまりグローバル役割ドメイン)に到達するまで、外層にネストされた役割ドメインを検索し続けます.【最外層への作用域が見つからない場合、エンジンはReferenceError異常を放出します.】

  • 注意:•エンジン:JavaScriptプログラム全体のコンパイルと実行を最初から最後まで担当します.•コンパイラ:エンジンの親友の一人で、文法分析やコード生成などの汚い仕事を担当しています.(コンパイル:構文解析-構文解析-コード生成.JavaScriptの場合、コンパイルはコード実行前の数マイクロ秒(さらに短い!))をクリックします.役割ドメイン:エンジンのもう一人の親友は、すべての宣言された識別子(変数)からなる一連のクエリーを収集し、維持し、現在実行されているコードのこれらの識別子へのアクセス権を決定する非常に厳しいルールを実施します.
    (2)LHS、RHS、ReferenceError、TypeError (p12)
  • LHSクエリは、変数を見つけようとするコンテナ自体(var a = 2aのような値付与動作の左側)であり、それによって値を付与する.
  • RHSクエリは、そのソース値を取得します.たとえば、console.log(a)は、aconsole.logの両方に対してRHSクエリを行う必要があります.
  • ReferenceError:役割ドメイン判別失敗に関連する.(以下詳細)
  • TypeError:役割ドメイン判別は成功したが,結果の操作は不正または不合理であることを示す.(以下詳細)
  • すべてのネストされた役割ドメインで必要な変数が見つからない場合、エンジンはRHS 異常を放出します.
  • ReferenceErrorで変数が見つかった場合、この変数の値を不合理に操作しようとします.たとえば、非関数タイプの値を関数呼び出したり、nullまたはundefinedタイプの値の属性を参照したりすると、エンジンはRHS 異常を放出します.
  • 【非厳格モード】TypeErrorが最上位(グローバル役割ドメイン)にもターゲット変数が見つからない場合、グローバル役割ドメインにその名前の変数(グローバル変数)が作成され、エンジンに返されます.
  • 【厳格モード】LHS が最上位レベル(グローバル役割ドメイン)でもターゲット変数が見つからない場合、グローバル変数が作成されずに返され、エンジンはLHS 異常を放出します.

  • 2.文法の役割ドメイン

  • 段組みの作用域(作用域気泡)
  • 文法作用域:簡単に言えば、文法作用域は文法段階に定義された作用域である.すなわち、文法的役割ドメインは、コードを書くときに変数とブロック的役割ドメインをどこに書くかによって決定されるので、文法解析器がコードを処理するときに役割ドメインを維持します(ほとんどの場合はそうです).
  • 詐欺語法作用域:ReferenceErroreval(..)関数ですが、この2つの方法はエンジンで最適化できないため、性能が低下し、推奨されません.

  • 3.関数の役割ドメインとブロックの役割ドメイン

  • 関数の役割ドメインの意味は、この関数に属するすべての変数が関数全体の範囲内で使用および多重化できることを意味する(実際にはネストされた役割ドメインでも使用できる).
  • ブロックの作用域:withwithtry/catch catchletconst
  • .

    4.字下げ

  • 関数宣言と変数宣言はいずれも昇格されます.
  • 変数は、たとえば、
  • などの昇格を宣言します.
    var a = 1;
    foo();
    function foo() {
        console.log( a ); // undefined 
        var a = 2;
    }
    

    次のようになります.
    function foo() { 
        var a;
        console.log( a ); // undefined
        a = 2; 
    }
    var a;
    a = 1;
    foo();
    
  • 関数優先:関数宣言と変数宣言はいずれも昇格されますが、関数はまず昇格され、次に変数になります.
  • 例えば
  • foo(); // 1
    var foo;
    function foo() {
      console.log(1);
    }
    foo = function() {
      console.log(2);
    }
    

    次のようになります.
    function foo() {
      console.log(1);
    }
    var foo; // , 
    foo(); // 1
    foo = function() {
      console.log(2);
    }
    

    5.作用域閉パッケージ


    (1)forサイクルにおけるletの妙用(p 51)
    forループヘッダのlet宣言には特殊な動作もあります.この動作は、変数がループ中に一度だけ宣言されるのではなく、反復のたびに宣言されることを示します.その後の各反復は、前の反復の終了時の値を使用してこの変数を初期化します.例:
    for(let i=1;i<=5;i++) {
      setTimeout(function() {
        console.log(i)
      },i*1000)
    }
    

    次のようになります.
    for(var i=1;i<=5;i++) {
      let j=i;
      setTimeout(function() {
        console.log(j)
      },j*1000)
    }
    

    (2)モジュール(p 53)
    モジュールモードは2つの必要条件を備える必要がある:1.外部の閉じた関数が必要です.この関数は少なくとも1回呼び出さなければなりません(呼び出すたびに新しいモジュールインスタンスが作成されます).2.クローズド関数は、少なくとも1つの内部関数を返さなければならない.これにより、内部関数は、プライベート役割ドメイン内でクローズドパッケージを形成し、プライベート状態にアクセスまたは変更することができる.【関数呼び出しから返される、閉パッケージ関数を持たないデータ属性のみのオブジェクトが真のモジュールではない】
  • モジュールは次のとおりです:
  • function CoolModule() {
      var something = "cool";
      var another = [1,2,3];
      function doSomething() {
        console.log(something);
      }
      function doAnother() {
        console.log(another.join());
      }
      return {
        doSomething: doSomething,
        doAnother: doAnother
      }
    }
    var foo = CoolModule();
    foo.doSomething(); // cool
    foo.doAnother(); // 1,2,3