スコープとスコープチェーン

3412 ワード

スコープ
JavaScriptには二つの作用領域があります.
  • グローバルスコープ
  • ローカルスコープ
  • 変数が一つの関数に定義されると、変数は局所的な作用領域にあり、関数以外の変数を定義すると大域的な作用領域に属します.各関数は呼び出し時に新しいスコープを作成します.
    グローバルスコープ
    最外層関数によって定義された変数はグローバルスコープを持ち、グローバルスコープ内の変数は他の作用領域でアクセスされたり変更されたりすることができます.
    var name = "Tennant";
    console.log(name);//Tennant
    
    function logName(){
        console.log(name);
    }
    logName();//Tennant
    
    ローカルスコープ
    グローバルスコープとは対照的に、ローカルスコープは一般的に固定コードセグメント内だけでアクセスできますが、関数の外部にはアクセスできません.最も一般的なのは関数の内部などです.
    function fn(){
        var name = "Tennant";
    }
    fn();
    console.log(name);//undefined
    
    関数内部で変数を宣言する場合は、必ずvarコマンドを使用します.使用しない場合は、グローバル変数を宣言します.
    function fn(){
        name = "Tennant";
    }
    fn();
    console.log(name);//Tennant
    
    また、下記のコードのように、関数内に局所変数が定義されている限り、関数は解析時にこの変数を「事前宣言」します.
    var scope = "global";
          function fn(){
             console.log(scope);//undefined
             var scope = "local";
             console.log(scope);//local
          }
          fn();
    
    var scope = "global";
          function fn(){
             var scope;//         
             console.log(scope);//undefined
             scope = "local";
             console.log(scope);//local
          }
          fn();
    
    ブロックレベルのスコープがありません.
    Javascriptには、ブロックレベルのスコープがありません.他のクラスCの言語では、括弧で閉じられたコードブロックは自分の役割領域があります.したがって、条件をサポートして変数を定義します.例えば、次の世代は望んだ結果を得られない:
    if(true){
        var name = "Tennant";
    }
    console.log(name);//Tennant
    
    ここではif文で変数nameを定義します.C、C+++またはJavaであれば、nameはif文の実行後に破棄されます.ただし、JavaScriptでは、if文の変数宣言は、現在の実行環境(ここではグローバル環境)に変数を追加します.for文を使う時は特に注意してください.例えば、
    for (var i = 0; i < 10; i++){
        doSomething(i);
    }
    console.log(i);//10
    
    ブロックレベルのスコープがある言語では、for文初期化変数の表現で定義された変数は、ループの環境にのみ存在します.JavaScriptについては、for文で作成された変数iは、forループ実行が終了しても、ループ外部の実行環境に存在します.
    スコープチェーン(Scope chain)
    コードが環境で実行されると、変数オブジェクトの作用ドメインチェーンが作成されます.作用するドメインチェーンの役割は、実行環境にアクセスできるすべての変数と関数に対する規則的なアクセスを保証することである.
    実行環境
    実行環境は、変数や関数がアクセスできる他のデータを定義し、それぞれの挙動を決定します.各実行環境には、関連する変数オブジェクトがあり、環境で定義されているすべての変数と関数がこのオブジェクトに保存されます.
    グローバル実行環境は最も周辺の実行環境であり、グローバル実行環境はwindowオブジェクトと見なされているので、すべてのグローバル変数と関数はwindowオブジェクトの属性と方法として作成されます.
    JavaScriptの実行順序は、関数の呼び出しによって決定され、関数が呼び出されると、その関数環境の変数オブジェクトが環境スタックに押し込まれる.関数が実行された後、スタックはその関数の変数オブジェクトをポップアップし、制御権を前の実行環境変数オブジェクトに渡す.
    例を挙げます
    var color = "blue";
    function changeColor(){
        if(color === "blue"){
            color = "red";
        }else{
            color = "blue";
        }
    }
    changeColor();
    alert(color);//red
    
    上記の例では、関数changeColor()の作用ドメインチェーンは、2つのオブジェクトを含む.
    独自の変数オブジェクト(argmentsオブジェクトが定義されています)とグローバル環境の変数オブジェクトです.関数内部で変数カラーにアクセスできるのは、このスコープ内で見つけられるからです.
    コードを見てください
    var a = 1
    function fn1(){  
      function fn2(){
        console.log(a)
      }
      function fn3(){
        var a = 4
        fn2()
      }
      var a = 2   
      return fn3   
    }
    var fn = fn1() 
    fn() //    
    
    //  a=2
    //  fn2  ,fn2     a,           fn2      fn1   a=2
    
    var a = 1
    function fn1(){
      function fn3(){
        function fn2(){
          console.log(a)
        }
        var a
        fn2()
        a = 4
      }      
      var a = 2
      return fn3
    }
    var fn = fn1()
    fn() //    
    
    //  undefined
    //  fn2       ,            ,              fn  ,          ,a         undefined
    
    以上の検索方向は以下の通りです.
  • 関数は実行中に、まず自分の内部から変数を探します.
  • が見つからなかったら、現在の関数が作成されているスコープから探します.