JavaScriptの基礎――作用領域と作用領域チェーンを深く理解する

5031 ワード

前言
万丈のビルは平地から始まります.基礎を学ぶことが大切です.
知識を前置きする
実行環境
実行環境はJavaScriptの中で最も重要な概念です.実行環境は、変数や関数がアクセスできる他のデータを定義し、それぞれの挙動を決定します.各実行環境には、関連する変数オブジェクトがあり、環境で定義されているすべての変数と関数がこのオブジェクトに保存されます.私たちが作成したコードはこのオブジェクトにアクセスできませんでしたが、解析器はデータを処理する際にバックグラウンドで使います.
各実行環境には環境オブジェクトがあります.
グローバル実行環境
グローバル実行環境は、最も周辺的な実行環境である.Webブラウザでは、グローバル実行環境はwindowオブジェクトとして認識されている.
グローバル環境はアプリケーションが終了するまで、ウェブページやブラウザを閉じたときなどに破壊されます.
関数実行環境
各関数は自分の実行環境を持っています.実行ストリームが関数に入ると、関数の環境が環境スタックに押し込まれます.
関数が実行された後、スタックはその環境をイジェクトし、制御権を前の実行環境に戻す.ECMAScriptプログラムの実行フローはこの便利なメカニズムによって制御されています.
スコープ
スコープは次のように分けられます.
  • グローバルスコープ
  • ローカルスコープ
  • ブロックレベルのスコープ(s 6)
  • 1.グローバルスコープ
    グローバル変数はグローバルスコープを持っています.変数と関数はwindowオブジェクトにマウントされます.
    var scope = 'global'; //         
    function checkScope () {
      var scope = 'local'; //           
      myscope = 'local';
      return scope;        //         ,          
    }
    
    window.myscope // undefined => checkScope()     ,      
    checkScope();  // local
    window.myscope // local
    2.ローカルスコープ
    局所変数は局所的な作用領域であり,関数の内部だけで有用である.
    var scope = 'global';
    function checkScope () {
      var scope = 'local';
      function nested() {
        var scope = 'nested';
        return scope;
      }
      return nested();
    }
    
    checkScope() // nested =>     nested()   scope 
    window.scope  // global =>      scope      
    3.スコープ優先度
    関数の内部の局所変数の優先度は、同じ名前のグローバル変数より高いです.同じ名前のグローバル変数は上書きされます.
    scope = 'global';    //         ,     var   
    function checkScope2 () {
      scope = 'local';   //         scope
      myscope = 'local'; //              
      return [scope, myscope];
    }
    
    checkScope2(); // [local, local] 
    window.scope; // local =>        
    window.myscope; // local =>         
    4.同名の変数
    var宣言変数がアップし、内部変数が外部変数をカバーする可能性があります.
    var tmp = '  ';
    
    function f() {
      console.log(tmp);
      if (false) {
        var tmp = 'hello world';
      }
    }
    f(); // undefined =>           “    ”
    事前に翻訳した後、if文内のtemp声明がアップされたからです.
    var tmp = '  ';
    
    function f() {
      var tmp 
      console.log(tmp); //      if      temp
      if (false) {
        tmp = 'hello world';
      }
    }
    f();
    5.ES 5模擬ブロックレベルのスコープ
    ES 5はブロックレベルのスコープがありません.不正な使用は変数の漏洩を引き起こす.
    for (var k = 0; k < 5; k++) {
      setTimeout(function () {
          console.log('inside', k);
      }, 1000);
    }
       
    console.log('outside', k); // outside 5  =>      ,k    for      ,        5,     k is not defined
    //   1s,    5  inside 5 =>      ,     0 1 2 3 4
    
    window.k; // 5 =>     k      ,      for       ,k      5 ,   k = 5
    もう一つ問題を出す
    var test = function() {
      var arr = [];
      for (var i = 0; i < 3; i++) {
        console.log('     ', i)
        arr[i] = function() {
          return i * i;
        };
      }
      return arr;
    };
     
    var a = test(); //    “      0 1 2” =>    arr[i]      ,i      3  
    a[1](); // 9
    a[2](); // 9
    ブロックレベルのスコープ
    前の紹介で、ES 5はブロックレベルの機能領域がないことが分かります.変数の使い方が間違っていて、変数が漏れやすく、不合理な場面が多いです.このような状況を避けるために、以下の方法が使えます.
    以下は全部対象ですES5 。 が挙げた例を修正する.
    1.すぐに関数を実行する
    for (var k = 0; k < 5; k++) { 
      (function(k){
        //        
        setTimeout(function (){
          console.log('inside', k);
         },1000);
      })(k);
    }
    
    console.log('outside', k);
    //    outside 5
    //       inside 0 1 2 3 4
    
    2.関数を定義して値を伝える
    var _loop = function _loop(k) {
      //        
      setTimeout(function () {
        console.log(k);
      }, 1000);
    };
    
    for (var k = 0; k < 5; k++) {
      _loop(k);
    }
    //      0 1 2 3 4 
    
    1、2の書き方はJSの関数伝達パラメータを利用しています.いずれも値伝達の特徴です.
    3.setTimeoutを使用する第三のパラメータ
    for (let k = 0; k < 5; k++) {
      setTimeout(function () {
          console.log(k);
      }, 1000, k);
    }
    //      0 1 2 3 4
    4.let、constを使って変数を宣言する
    for (let k = 0; k < 5; k++) {
      setTimeout(function () {
          console.log(k);
      }, 1000);
    }
       
    console.log(k); // k is not defined
    //   1s,    inside 0 1 2 3 4
    実行手順に注意
    スコープチェーン
    コードが環境で実行されると、変数オブジェクトのスコープチェーンが作成されます.
  • 作用分域チェーンの用途は、実行環境にアクセスできるすべての変数と関数に関する規則的なアクセスを保証することである.
  • 作用分域チェーンの先端は、常に現在実行されているコードが存在する環境の変数オブジェクトです.この環境が関数である場合、その活動対象を変数オブジェクトとします.活動対象は最初に一つの変数だけを含んでいます.つまり、argmentsオブジェクト(このオブジェクトはグローバル環境には存在しません.)
  • スコープ内の次の変数オブジェクトは、含まれる(外部)環境から来ます.次の変数オブジェクトは、次の環境を含む環境から来ます.このようにして、グローバル実行環境まで継続します.
  • グローバル実行環境の変数オブジェクトは、常に、スコープ内の最後のオブジェクトである.
  • 上の説明は「JavaScript権威の手引き」のマニュアルから抜粋したものです.
    簡単にまとめると、
    変数を使うと、まず現在のスコープから探します.見つけられないなら上に探して、大域的なスコープを見つけても見つからないなら、エラーを投げます.この変数がないと説明します.このような層の関係はドメインチェーンの役割です.
    var a = 100
    function F1() {
        var b = 200
        function F2() {
            var c = 300
            console.log(a) // 100            
            console.log(b) // 200            
            console.log(c) // 300        
            console.log(d) // ReferenceError:d is not defined   window    ,     ,  
        }
        F2()
    }
    F1()