web-dev-qa-db-ja.com

JavaScriptのスコープチェーン

私はJavaScriptでスコープチェーンを読みましたが、それは私には何の意味もありませんでした。私はそれをググりましたが、私は理解できる何かを見つけませんでした:(

53
Tarik

スコープチェーンを理解するには、クロージャがどのように機能するかを知っている必要があります。

関数をネストするとクロージャが形成され、内部関数は、親関数がすでに実行された後でも、外部の囲み関数に存在する変数を参照できます。

JavaScriptは、スコープチェーンを上に移動してローカルからグローバルに移動することにより、特定のコンテキスト内の識別子を解決します。

3つのネストされた関数を持つこの例を考えてみます。

var currentScope = 0; // global scope
(function () {
  var currentScope = 1, one = 'scope1';
  alert(currentScope);
  (function () {
    var currentScope = 2, two = 'scope2';
    alert(currentScope);
    (function () {
      var currentScope = 3, three = 'scope3';
      alert(currentScope);
      alert(one + two + three); // climb up the scope chain to get one and two
    }());
  }());
}());

推奨読書:

57
CMS

ECMAScript(JSのベースとなっているコア言語)の関数呼び出しは、個別に実行される個別の実行コンテキストを生成します。各実行コンテキスト内では、thisは問題のオブジェクトを参照し、デフォルトでは関数がアタッチされているものに設定されます。

function foo() {
    alert(this===window)
}

ウィンドウは「foo」メソッドを所有するオブジェクトであるため、trueと警告します。関数で定義された変数は、その関数の一意のスコープチェーンである環境を通じてアクセスされます。

function world() {
    var name = 'global';
    alert(name)
}

明らかに「グローバル」に警告します。

function world() {
    var name = 'global';
    (function() {
        var name = 'country';
        alert(name)
    })();
    alert(name)
}

最新の例では、最初のアラートが呼び出されると、JavaScriptは内部関数のスコープチェーンで識別子nameが定義されていると判断するため、スコープチェーンを調べて取得する必要はありません。 。

2番目のアラート呼び出しでは、nameも同じコンテキストで定義され、「グローバル」にアラートを出します。

function world() {
    var name = 'global';
    (function() { alert(name) })();
}

この例では、name識別子は同じコンテキストで定義されていないため、スコープチェーンを上に向かって名前が定義されている外部関数に移動する必要があり、グローバルにアラートを出します。

参照:

17
meder omuraliev

私はそれが古い投稿であることを知っていますが、それでも開発者には役立ちます。初心者の方がスコープチェーンを理解しやすいので、少し違う方法でやりたかったのです。これが私の変更されたバージョンのコードです:

var currentScope = 0; // global scope
function a () {
   var currentScope = 1, one = 'scope1';
   alert(currentScope);

  function b () {
      var currentScope = 2, two = 'scope2';
      alert(currentScope);

      function c () {
         var currentScope = 3, three = 'scope3';
         alert(currentScope);
  alert(one + two + three); // climb up the scope chain to get one and two
     }
     c();
  }
  b();
}
a();
5
JVM

これは閉鎖についてです。内部スコープでスコープ外の変数を使用できます。

function get_inner_scope () {
    var outer = 'Outer variable value';
    return function () {
        alert(outer);
    }
}
f = get_inner_scope();
f(); // alerts Outer variable value

最初のgoogleのリンクによる他のサンプルの詳細情報: http://blogs.msdn.com/jscript/archive/2007/07/26/scope-chain-of-jscript-functions.aspx

5
Anatoliy

素人の言葉で説明されるJavaScriptのスコープチェーン

アレックスは幸せな男です、ある晴れた日、彼の毎月の給料を手にして道を歩いていきます。

後に彼は、明日が彼の娘の授業料1000ドルを支払う最後の日であることを理解します。
彼は家に帰り、400ドルの節約を見つけ、残り(600ドル)を心配します。
お金のない貧しい大工であるマシューは、継承したブレスレットを300ドルで売り、息子のアレックスに貸します。
社会で定評のあるアレックスは、残りの300ドルを地元の銀行からすぐに受け取り、予定通りに娘の授業料を支払います。

JavaScriptのスコープチェーンに戻ります:
JavaScriptのAlex-A関数
マシュー-即時機能であるアレックスがネストされています。
Mathewsの親-Mathewがネストされている即時関数.
バンクグローバル変数。

function Bank() {
    loan=300;
    Mathew();

    function Mathew() {
        mathew=300;
        Alex();

        function Alex() {
            savings:400;
            alert('I need some money');
        }

    }

}

Bank();

この時点でのアレックスのスコープチェーンは次のようになります。[savings:400] + [mathew:300] + [loan:300];

3
Sai Chandra

概要:

スコープチェーンは、JavaScriptの変数名の値を解決するために使用されます。スコープチェーンがないと、異なるスコープで複数が定義されている場合、JavaScriptエンジンは特定の変数名にどの値を選択するかを認識できません。 JavaScriptのスコープチェーンは字句的に定義されています。これは、コードを見てスコープチェーンがどうなるかを確認できることを意味します。

スコープチェーンの最上部はグローバルスコープで、ブラウザーのwindowオブジェクトです(globalNodeJS)。グローバルスコープの他に、関数には独自の変数スコープがあります。スコープチェーンは、関数が定義されている場所を確認することで決定できます。

変数を解決するとき、内部関数はまず自身のスコープを調べます。変数が独自のスコープ内で見つからない場合、スコープチェーンを登り、関数が定義された環境で変数名を探します。これは次のようになります。

Scope chain javascript

したがって、画像の例では、innerFooが変数barを使用する場合、最初にinnerFoo(関数本体内のコード)のスコープ内で変数を見つけようとします。次に、ここで見つからない場合スコープチェーンfooに登ります。 fooには、barという名前の変数もありません。したがって、スコープチェーンを上って、グローバルスコープを調べます。グローバルスコープには、barが解決される値10を持つbarという名前の変数があります。

例:

let foo = 1;
let bar = 1;


function test (bar) {
   
   return function innerTestFunc () {
      let foo = 10;
      
      console.log(foo, bar);
    }
  
}

const innerTestFunc1 = test(5);
const innerTestFunc2 = test(20);


innerTestFunc1();  // logs 10, 5

innerTestFunc2();  // logs 10, 20

上記の例では、関数を返す関数があります。最初に、この関数を変数innerTestFunc1およびinnerTestFunc2に格納します。これにより、基本的に外部環境のスコープチェーンのスナップショットであるclosureが作成されます。

次に、関数が実行されると、関数は変数foobarの両方の値を必要とします。 fooの値はinnerTestFuncのレベルで解決でき、両方とも10です。 10はinnerFooですでに見つかっているので、fooのスコープチェーンを登る必要はありません。

bar変数の場合、関数はinnerFooでそれを見つけることができません。したがって、スコープチェーンを上ります。最初に関数barで変数testを検出します。したがって、barの値をテスト関数の値に解決します(この例では5、20)。 。

1