web-dev-qa-db-ja.com

JavaScriptの変数の範囲は何ですか?

JavaScriptの変数の範囲は何ですか?それらは関数の外側とは反対に内側で同じスコープを持っていますか?それとも重要なのですか?また、グローバルに定義されている場合、変数はどこに格納されますか?

1873
lYriCAlsSH

私ができる最善のことは、勉強するためのたくさんの例をあげることだと思います。 Javascriptプログラマは実際には範囲をどの程度理解しているかによってランク付けされます。それは時々かなり直観的ではないかもしれません。

  1. グローバルスコープの変数

    // global scope
    var a = 1;
    
    function one() {
      alert(a); // alerts '1'
    }
    
  2. ローカルスコープ

    // global scope
    var a = 1;
    
    function two(a) { // passing (a) makes it local scope
      alert(a); // alerts the given argument, not the global value of '1'
    }
    
    // local scope again
    function three() {
      var a = 3;
      alert(a); // alerts '3'
    }
    
  3. 中級 JavaScriptのブロックスコープのようなものはありません(ES5; ES6では let が導入されました)

    a。

    var a = 1;
    
    function four() {
      if (true) {
        var a = 4;
      }
    
      alert(a); // alerts '4', not the global value of '1'
    }
    

    b。

    var a = 1;
    
    function one() {
      if (true) {
        let a = 4;
      }
    
      alert(a); // alerts '1' because the 'let' keyword uses block scoping
    }
    
  4. 中級 オブジェクトプロパティ

    var a = 1;
    
    function Five() {
      this.a = 5;
    }
    
    alert(new Five().a); // alerts '5'
    
  5. 詳細 終了

    var a = 1;
    
    var six = (function() {
      var a = 6;
    
      return function() {
        // JavaScript "closure" means I have access to 'a' in here,
        // because it is defined in the function in which I was defined.
        alert(a); // alerts '6'
      };
    })();
    
  6. 上級 プロトタイプベースのスコープ解決

    var a = 1;
    
    function seven() {
      this.a = 7;
    }
    
    // [object].prototype.property loses to
    // [object].property in the lookup chain. For example...
    
    // Won't get reached, because 'a' is set in the constructor above.
    seven.prototype.a = -1;
    
    // Will get reached, even though 'b' is NOT set in the constructor.
    seven.prototype.b = 8;
    
    alert(new seven().a); // alerts '7'
    alert(new seven().b); // alerts '8'
    

  7. グローバル+ローカル さらに複雑な場合

    var x = 5;
    
    (function () {
        console.log(x);
        var x = 10;
        console.log(x); 
    })();
    

    JavaScriptは常に変数宣言(初期化ではない)をスコープの先頭に移動するので、これは10および5ではなくundefinedおよび10を出力します。コードは次のようになります。

    var x = 5;
    
    (function () {
        var x;
        console.log(x);
        x = 10;
        console.log(x); 
    })();
    
  8. キャッチ句スコープ変数

    var e = 5;
    console.log(e);
    try {
        throw 6;
    } catch (e) {
        console.log(e);
    }
    console.log(e);
    

    これは565を出力します。 catch節の中eはグローバル変数とローカル変数を隠します。しかし、この特別な範囲は捕捉された変数のためだけのものです。 catch句の中にvar f;を書くと、try-catchブロックの前後に定義したのとまったく同じになります。

2403
Triptych

Javascriptはスコープチェーンを使用して特定の機能のスコープを確立します。通常は1つのグローバルスコープがあり、定義された各関数には独自のネストスコープがあります。他の関数内で定義された関数はすべて、外部関数にリンクされているローカルスコープを持ちます。スコープを定義するのは、常にソース内の位置です。

スコープチェーン内の要素は基本的に、その親スコープへのポインタを持つMapです。

変数を解決するとき、javascriptは最も内側のスコープから開始して外側に検索します。

231
krosenvold

グローバルに宣言された変数にはグローバルスコープがあります。関数内で宣言された変数はその関数にスコープされ、同じ名前のグローバル変数をシャドウします。

(実際のJavaScriptプログラマーが他の回答で指摘できる微妙な点がたくさんあると確信しています。特に、私は このページ いつでもthisが正確に何を意味するかについて知りました。うまくいけば この入門リンク で開始できます。)

107
Jon Skeet

オールドスクールJavaScript

伝統的に、JavaScriptは実際には2種類のスコープしかありません。

  1. グローバルスコープ :変数は、アプリケーションの最初からアプリケーション全体で認識されています(*)
  2. 機能的範囲 :変数は 関数内で認識されています 関数の先頭から宣言されています(*)

違いを説明する他の多くの答えがすでにあるので、私はこれについては詳述しません。


現代のJavaScript

最新のJavaScript仕様 では、3番目のスコープも使用できます。

  1. ブロックスコープ :変数は ブロック内で認識されています それらはそれ以降宣言された瞬間から宣言されます(**)

ブロックスコープ変数を作成する方法

伝統的に、あなたはこのようにあなたの変数を作成します:

var myVariable = "Some text";

ブロックスコープ変数は次のように作成されます。

let myVariable = "Some text";

それでは、機能的スコープとブロックスコープの違いは何ですか?

機能範囲とブロック範囲の違いを理解するために、次のコードを検討してください。

// i IS NOT known here
// j IS NOT known here
// k IS known here, but undefined
// l IS NOT known here

function loop(arr) {
    // i IS known here, but undefined
    // j IS NOT known here
    // k IS known here, but has a value only the second time loop is called
    // l IS NOT known here

    for( var i = 0; i < arr.length; i++ ) {
        // i IS known here, and has a value
        // j IS NOT known here
        // k IS known here, but has a value only the second time loop is called
        // l IS NOT known here
    };

    // i IS known here, and has a value
    // j IS NOT known here
    // k IS known here, but has a value only the second time loop is called
    // l IS NOT known here

    for( let j = 0; j < arr.length; j++ ) {
        // i IS known here, and has a value
        // j IS known here, and has a value
        // k IS known here, but has a value only the second time loop is called
        // l IS NOT known here
    };

    // i IS known here, and has a value
    // j IS NOT known here
    // k IS known here, but has a value only the second time loop is called
    // l IS NOT known here
}

loop([1,2,3,4]);

for( var k = 0; k < arr.length; k++ ) {
    // i IS NOT known here
    // j IS NOT known here
    // k IS known here, and has a value
    // l IS NOT known here
};

for( let l = 0; l < arr.length; l++ ) {
    // i IS NOT known here
    // j IS NOT known here
    // k IS known here, and has a value
    // l IS known here, and has a value
};

loop([1,2,3,4]);

// i IS NOT known here
// j IS NOT known here
// k IS known here, and has a value
// l IS NOT known here

ここで、変数jは最初のforループでのみ認識され、前後には認識されないことがわかります。しかし、変数iは関数全体で知られています。

また、ブロックスコープ変数は、ホイストされていないため、宣言される前には認識されていないことを考慮してください。同じブロック内で同じブロックスコープの変数を再宣言することもできません。これにより、ブロックスコープの変数は、グローバルスコープまたは関数スコープの変数よりもエラーが発生しにくくなります。これらの変数は、複数の宣言があってもエラーが発生しません。


今日ブロックスコープ変数を使用しても安全ですか?

今日使用しても安全かどうかは、環境によって異なります。

  • サーバーサイドのJavaScriptコード( Node.js )を書いている場合は、安全にletステートメントを使用できます。

  • クライアントサイドのJavaScriptコードを書いていて、ブラウザベースのtranspiler( Traceur または babel-standalone のように)を使っているなら、安全に使えます。 letステートメント、しかしあなたのコードはパフォーマンスに関して最適以外のものになるでしょう。

  • クライアントサイドのJavaScriptコードを書いていて、Nodeベースのtranspiler( traceurシェルスクリプト または Babel のような)を使っているなら、安全に使えます。 letステートメントそして、あなたのブラウザは変換されたコードだけを知っているので、パフォーマンスの欠点は制限されるべきです。

  • クライアントサイドのJavaScriptコードを書いていてトランスパイラーを使用していない場合は、ブラウザのサポートを考慮する必要があります。

    これらはletをまったくサポートしていないブラウザです。

    • Internet Explorer 10 以下
    • Firefox 43 以下
    • Safari 9 以下
    • Androidブラウザ4 以下
    • オペラ27 以下
    • 40丁目 以下
    • Opera Mini Blackberryブラウザ のいずれかのバージョン

enter image description here


ブラウザサポートを追跡する方法

この回答を読んだ時点でどのブラウザがletステートメントをサポートしているかについての最新の概要は、 このCan I Useページ を参照してください。


(*)JavaScript変数は hoisted であるため、グローバルスコープおよび機能スコープの変数は宣言前に初期化して使用できます。これは宣言が常にスコープの最上位にあることを意味します。

(**)ブロックスコープ変数は持ち上げられません

68
John Slegers

これが例です:

<script>

var globalVariable = 7; //==window.globalVariable

function aGlobal( param ) { //==window.aGlobal(); 
                            //param is only accessible in this function
  var scopedToFunction = {
    //can't be accessed outside of this function

    nested : 3 //accessible by: scopedToFunction.nested
  };

  anotherGlobal = {
    //global because there's no `var`
  }; 

}

</script>

あなたはクロージャを調査し、そして プライベートメンバ を作るためにそれらをどのように使用するかを知りたいでしょう。

38
geowa4

私が理解しているように、重要な点は、Javascriptがより一般的なCブロックの有効範囲に対して関数レベルの有効範囲を持つことです。

これは主題に関する良い記事です。

31
James McMahon

"Javascript 1.7"(MozillaのJavascriptの拡張)では、 letステートメント を使ってブロックスコープ変数を宣言することもできます。

 var a = 4;
 let (a = 3) {
   alert(a); // 3
 }
 alert(a);   // 4
26
kennytm

Brendan Eich によって最初に設計されたときのJavaScriptでのスコープの考えは HyperCard スクリプト言語 HyperTalk から来ました。

この言語では、表示はインデックスカードのスタックと同様に行われました。背景と呼ばれるマスターカードがありました。それは透明で、一番下のカードとして見ることができます。このベースカードの内容は、その上に置かれているカードと共有されていました。一番上に置かれた各カードは、前のカードよりも優先される独自のコンテンツを持っていましたが、必要に応じて前のカードにアクセスできました。

これがまさにJavaScriptスコープシステムの設計方法です。名前が違うだけです。 JavaScriptのカードはとして知られています実行コンテキストECMA 。これらの各コンテキストには、3つの主要部分があります。可変環境、字句環境、およびこのバインディング。カードのリファレンスに戻ると、字句環境には、スタックの下位にある以前のカードのすべてのコンテンツが含まれています。現在のコンテキストはスタックの最上位にあり、そこで宣言されたコンテンツはすべて変数環境に格納されます。命名の衝突の場合は、可変環境が優先されます。

Thisバインディングは、それを含むオブジェクトを指します。包含オブジェクトがwindowまたはコンストラクタ関数である可能性がある宣言済み関数のように、スコープまたは実行コンテキストが包含オブジェクトを変更せずに変更されることがあります。

これらの実行コンテキストは、制御が転送されるたびに作成されます。コードの実行開始時に制御が移され、これは主に関数の実行から行われます。

これが技術的な説明です。実際には、JavaScriptでそれを覚えておくことが重要です

  • スコープは技術的には「実行コンテキスト」です。
  • コンテキストは変数が格納される環境のスタックを形成します
  • スタックの一番上が優先されます(一番下がグローバルコンテキストです)。
  • 各関数は実行コンテキストを作成します(ただし、常に新しいthisバインディングとは限りません)。

このページの前の例(5. "クロージャ")の1つにこれを適用すると、実行コンテキストのスタックに従うことができます。この例では、スタック内に3つのコンテキストがあります。それらは、外側の文脈、var sixによって呼び出されたすぐに呼び出された関数内の文脈、およびvar 6のすぐに呼び出された関数内の返された関数内の文脈によって定義されます。

i)外側のコンテキスト。 a = 1の可変環境です。
ii)IIFEコンテキストでは、a = 1の字句環境がありますが、スタックで優先されるa = 6の可変環境があります。
iii)返された関数コンテキスト。これはa = 6の字句環境を持ち、それは呼び出されたときにアラートで参照される値です。

enter image description here

22
Travis J

1)グローバルスコープ、関数スコープ、withスコープとcatchスコープがあります。変数の一般的な 'ブロック'レベルのスコープはありません - withとcatchステートメントはそれらのブロックに名前を追加します。

2)スコープはグローバルスコープに至るまで関数によってネストされています。

3)プロパティはプロトタイプチェーンをたどることによって解決されます。 with文は、オブジェクトプロパティ名をwithブロックで定義されている字句スコープに入れます。

編集:ECMAAScript 6(ハーモニー)はletをサポートするように指定されています、そして私はchromeが 'ハーモニー'フラグを許可することを知っているので、おそらくそれはそれをサポートします..

ブロックレベルのスコープをサポートするようにしましょうが、それを実現するにはキーワードを使用する必要があります。

編集:コメントの中でwithとcatch文からベンジャミンの指摘を基に、私は記事を編集し、より多くを追加しました。 withとcatchの両方のステートメントはそれぞれのブロックに変数を導入します、そして - ブロックスコープです。これらの変数は、それらに渡されるオブジェクトのプロパティにエイリアスされています。

 //chrome (v8)

 var a = { 'test1':'test1val' }
 test1   // error not defined
 with (a) { var test1 = 'replaced' }
 test1   // undefined
 a       // a.test1 = 'replaced'

編集:明確な例:

test1はwithブロックをスコープとしていますが、a.test1にエイリアスされています。 'Var test1'は、それがaのプロパティでない限り、上位の字句コンテキスト(関数、またはグローバル)に新しい変数test1を作成します。

いいね! 'with'の使用には注意してください。変数がすでに関数内で定義されている場合は、varがnoopであるのと同じように、オブジェクトからインポートされた名前に関してもnoopです。すでに定義されている名前に少し頭を向けると、これははるかに安全になります。私は個人的にこれのために決して使わないでしょう。

17
Gerard ONeill

JavaScriptに慣れていない人の多くは、継承は言語でデフォルトで利用可能であり、関数のスコープはこれまでのところ唯一のスコープであるということを理解するのに苦労しています。私は昨年末に書いた美人にJSPrettyという拡張子を付けました。機能色はコード内でスコープを機能させ、そのスコープ内で宣言されているすべての変数に常に色を関連付けます。あるスコープの色を持つ変数が別のスコープで使用されていると、クロージャが視覚的に示されます。

この機能を試してください。

でデモを見る:

コードを見てください。

現在、この機能は16の入れ子関数の深さをサポートしていますが、現在グローバル変数に色を付けていません。

10
austincheney

JavaScriptには2種類のスコープしかありません。

  1. グローバルスコープ :グローバルはウィンドウレベルのスコープに過ぎません。ここで、アプリケーション全体に存在する変数です。
  2. 機能範囲 varキーワードを使用して関数内で宣言された変数には機能範囲があります。

関数が呼び出されるたびに、変数スコープオブジェクトが作成され(スコープチェーンに含まれ)、その後にJavaScriptの変数が続きます。

        a = "global";
         function outer(){ 
              b = "local";
              console.log(a+b); //"globallocal"
         }
outer();

スコープチェーン - >

  1. ウィンドウレベル - スコープチェーンのaおよびouter関数はトップレベルにあります。
  2. 外部関数が新しいvariable scope object(およびスコープチェーンに含まれる)を呼び出し、その中に変数bが追加されたとき。

これで、変数aが最初に最も近い変数スコープを検索し、variableがそこにない場合、それは変数スコープチェーンの次のオブジェクトに移動します。

9
Anshul

他の答えに加えて、scopeは宣言されたすべての識別子(変数)のルックアップリストであり、これらが現在実行中のコードにどのようにアクセス可能かについての一連の厳密な規則を強制します。この検索は、LHS(左側)参照である変数への代入を目的としている場合もあれば、RHS(右側)参照である値の取得を目的としている場合もあります。これらのルックアップは、コードをコンパイルして実行するときにJavaScriptエンジンが内部的に行っていることです。

この観点から、私はKyle SimpsonのScopes and Closures電子ブックで私が見つけた写真が役に立つと思う。

image

彼の電子ブックからの引用:

建物は、プログラムのネストされたスコープルールセットを表します。建物の1階は、どこにいても、現在実行中のスコープを表します。建物の最上位レベルはグローバルスコープです。 LHSおよびRHSの参照を解決するには、現在の階を調べ、それが見つからない場合は、エレベーターを次の階に移動し、そこを見て、次に次のようにします。最上階(グローバルスコープ)にたどり着くと、探しているものが見つかるか、いないかのどちらかになります。しかし、あなたは無関係にやめなければなりません。

「スコープの検索は、最初の一致が見つかると停止します」という1つの注目すべき点があります。

この「スコープレベル」の考え方は、ネストされた関数で検索されている場合に、なぜこれが新しく作成されたスコープで変更されるのかを説明します。ここにこれらの詳細すべてに入るリンクがあります、 あなたがjavascriptの範囲について知りたいことすべて

9
James Drinkard

グローバルスコープ:

グローバル変数はグローバルスターとまったく同じです(Jackie Chan、Nelson Mandela)。あなたは、あなたのアプリケーションのどの部分からでもそれらにアクセスすることができます(値を取得または設定)。グローバル機能は、グローバルイベント(新年、クリスマス)のようなものです。あなたはあなたのアプリケーションのどの部分からでもそれらを実行(呼び出し)することができます。

//global variable
var a = 2;

//global function
function b(){
   console.log(a);  //access global variable
}

ローカルスコープ:

あなたがアメリカにいるならば、あなたはキムカーダシアン、悪名高い有名人(彼女はどういうわけかタブロイドを作ることに成功した)を知っているかもしれません。しかし、アメリカ国外の人々は彼女を認めないでしょう。彼女は彼女の領土に縛られ、地元のスターです。

局所変数は局所星のようなものです。スコープ内でのみアクセスできます(値を取得または設定)。ローカル関数はローカルイベントに似ています - あなたはそのスコープ内でのみ実行(祝う)できます。範囲外からアクセスしたい場合は、参照エラーが発生します。

function b(){
   var d = 21; //local variable
   console.log(d);

   function dog(){  console.log(a); }
     dog(); //execute local function
}

 console.log(d); //ReferenceError: dddddd is not defined    

範囲の詳細な理解のためにこの記事をチェックしなさい

8
KhanSharp

コードを実行してください。これがスコープについての考えを与えることを願っています

Name = 'global data';
document.Name = 'current document data';
(function(window,document){
var Name = 'local data';
var myObj = {
    Name: 'object data',
    f: function(){
        alert(this.Name);
    }
};

myObj.newFun = function(){
    alert(this.Name);
}

function testFun(){
    alert("Window Scope : " + window.Name + 
          "\nLocal Scope : " + Name + 
          "\nObject Scope : " + this.Name + 
          "\nCurrent document Scope : " + document.Name
         );
}


testFun.call(myObj);
})(window,document);
8

ALMOSTには2種類のJavaScriptスコープしかありません。

  • 各var宣言の有効範囲は、最もすぐ外側にある関数に関連付けられています。
  • var宣言のための囲み関数がない場合、それはグローバルスコープです。

そのため、関数以外のブロックは新しいスコープを作成しません。これが、forループが外部スコープの変数を上書きする理由を説明しています。

var i = 10, v = 10;
for (var i = 0; i < 5; i++) { var v = 5; }
console.log(i, v);
// output 5 5

代わりに関数を使う:

var i = 10, v = 10;
$.each([0, 1, 2, 3, 4], function(i) { var v = 5; });
console.log(i,v);
// output 10 10

最初の例では、ブロックの有効範囲がなかったため、最初に宣言された変数が上書きされました。 2番目の例では、関数による新しいスコープがあり、最初に宣言された変数はSHADOWEDで上書きされませんでした。

JavaScriptのスコープに関して、知っておくべきことはほとんどそれだけです。

ですから、JavaScriptのスコープは実際には非常に単純ですが、必ずしも直感的ではありません。注意すべきことがいくつかあります。

  • var宣言はスコープの先頭に持ち上げられます。これは、var宣言がどこで行われても、コンパイラにとっては、var自体が先頭で行われているかのようになります。
  • 同じスコープ内の複数のvar宣言が結合されている

だから、このコード:

var i = 1;
function abc() {
  i = 2;
  var i = 3;
}
console.log(i);     // outputs 1

以下と同等です。

var i = 1;
function abc() {
  var i;     // var declaration moved to the top of the scope
  i = 2;
  i = 3;     // the assignment stays where it is
}
console.log(i);

これは直感に反するように思えるかもしれませんが、命令型言語設計者の観点からは理にかなっています。

6
jackbean818

Modern Js、ES6 +、 'const'および 'let'

他のほとんどの主要言語と同じように、作成するすべての変数にブロックスコープを使用する必要があります。 var 廃止された です。これにより、コードの安全性と保守性が向上します。

const 95%の場合に使用されるべきです 。変数 reference が変更できないようにするためです。配列、オブジェクト、およびDOMノードのプロパティは変更される可能性があり、おそらくconstになります。

letは、再割り当てが必要な変数に使用する必要があります。これにはforループが含まれます。初期化を超えて値を変更したことがある場合は、letを使用してください。

ブロック有効範囲は、変数が宣言されている括弧内でのみ使用可能になることを意味します。これは、あなたのスコープ内で作成された無名関数を含む内部スコープにも及びます。

5
Gibolt

JSには関数スコープしかありません。スコープをブロックしないでください。あなたは何も持ち上げているのか見ることができます。

var global_variable = "global_variable";
var hoisting_variable = "global_hoist";

// Global variables printed
console.log("global_scope: - global_variable: " + global_variable);
console.log("global_scope: - hoisting_variable: " + hoisting_variable);

if (true) {
    // The variable block will be global, on true condition.
    var block = "block";
}
console.log("global_scope: - block: " + block);

function local_function() {
    var local_variable = "local_variable";
    console.log("local_scope: - local_variable: " + local_variable);
    console.log("local_scope: - global_variable: " + global_variable);
    console.log("local_scope: - block: " + block);
    // The hoisting_variable is undefined at the moment.
    console.log("local_scope: - hoisting_variable: " + hoisting_variable);

    var hoisting_variable = "local_hoist";
    // The hoisting_variable is now set as a local one.
    console.log("local_scope: - hoisting_variable: " + hoisting_variable);
}

local_function();

// No variable in a separate function is visible into the global scope.
console.log("global_scope: - local_variable: " + local_variable);
4
koredalin

私の理解するところは、3つのスコープがあるということです:グローバルスコープ、グローバルに利用可能。ローカルスコープ。ブロックに関係なく関数全体で利用できます。ブロック有効範囲。それが使用されたブロック、ステートメント、または式でのみ使用可能です。グローバルスコープとローカルスコープは、関数内または外部でキーワード 'var'で示され、ブロックスコープはキーワード 'let'で示されます。

グローバルスコープとローカルスコープしかないと信じる人のために、なぜMozillaがJSのブロックスコープのニュアンスを説明するページ全体を持つのか説明してください。

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let

3
mrmaclean89

この好奇心旺盛な例を試してください。以下の例では、aが0で初期化された数値ならば、0と1が表示されます。その結果、両方とも同じアラートが表示されます。

var a = new Date();
function f1(b)
{
    b.setDate(b.getDate()+1);
    alert(b.getDate());
}
f1(a);
alert(a.getDate());
3
Mig82

JavaScriptには2種類のスコープがあります。

  • ローカルスコープ
  • グローバルスコープ

Below関数はローカルスコープ変数carNameを持ちます。そしてこの変数は関数の外側からはアクセスできない。

function myFunction() {
    var carName = "Volvo";
    alert(carName);
    // code here can use carName
}

Belowクラスには、グローバルスコープ変数carNameがあります。そしてこの変数はクラスのどこからでもアクセス可能です。

class {

    var carName = " Volvo";

    // code here can use carName

    function myFunction() {
        alert(carName);
        // code here can use carName 
    }
}
2
Abdur Rahman

ES5以前:

Javascriptの変数は、最初は(ES6より前)字句関数スコープでした。語彙スコープという用語は、コードを「見る」ことによって変数の範囲を見ることができることを意味します。

varキーワードで宣言されたすべての変数は、関数の範囲にあります。ただし、その関数内で他の関数が宣言されている場合、それらの関数は外部関数の変数にアクセスできます。これは スコープチェーン と呼ばれます。これは次のように機能します。

  1. 関数が変数値を解決しようとすると、まず自分自身のスコープを調べます。これは関数本体、すなわち中括弧{}の間のすべてのものです(この範囲内にある other functions 内の変数を除く)。
  2. 関数本体の中に変数が見つからない場合は、 がチェーン に上がり、関数が定義されている の関数内の変数の有効範囲を調べます 。これは字句スコープで意味されるものです、我々はこの関数が定義されたところでコードで見ることができます、そしてそれ故に単にコードを見ることによってスコープチェーンを決定することができます。

例:

// global scope
var foo = 'global';
var bar = 'global';
var foobar = 'global';

function outerFunc () {
 // outerFunc scope
 var foo = 'outerFunc';
 var foobar = 'outerFunc';
 innerFunc();
 
 function innerFunc(){
 // innerFunc scope
  var foo = 'innerFunc';
  console.log(foo);
  console.log(bar);
  console.log(foobar);
  }
}

outerFunc();

変数foobar、およびfoobarをコンソールに記録しようとすると、次のようになります。

  1. コンソールにfooを記録しようとします、fooは関数innerFunc自身の中にあります。したがって、fooの値は文字列innerFuncに解決されます。
  2. コンソールにバーを記録しようとしています、バーは関数innerFunc自体の中に見つかりません。したがって、 スコープチェーン を登る必要があります。最初に、関数innerFuncが定義されている外部関数を調べます。これは関数outerFuncです。 outerFuncの範囲内で、文字列 'outerFunc'を保持する変数barを見つけることができます。
  3. foob​​arがinnerFuncに見つかりません。 。したがって、 スコープチェーン をinnerFuncスコープに登る必要があります。ここでも見つけることができません、我々は グローバルスコープ (すなわち、最も外側のスコープ)にもう一つのレベルを登ります。ここでは、文字列 'global'を保持する変数foobarを見つけます。スコープチェーンを登っても変数が見つからなかった場合、JSエンジンは referenceError をスローします。

ES6(ES 2015)以前:

字句的スコープとスコープの同じ概念がES6にも当てはまります。しかし、変数を宣言する新しい方法が導入されました。以下があります。

  • let:ブロックスコープの変数を作成します
  • const:初期化する必要があり、再割り当てできないブロックスコープの変数を作成します

varlet/constの最大の違いは、varは関数スコープであり、let/constはブロックスコープであるということです。これを説明する例を次に示します。

let letVar = 'global';
var varVar = 'global';

function foo () {
  
  if (true) {
    // this variable declared with let is scoped to the if block, block scoped
    let letVar = 5;
    // this variable declared with let is scoped to the function block, function scoped
    var varVar = 10;
  }
  
  console.log(letVar);
  console.log(varVar);
}


foo();

上記の例では、letで宣言された変数はブロックスコープであるため、letVarは値globalをログに記録します。それらはそれぞれのブロックの外側に存在しなくなるので、変数はifブロックの外側にアクセスすることはできません。

1

ECMAScript 6ではletおよびconstキーワードが導入されました。これらのキーワードは、varキーワードの代わりに使用できます。 varキーワードとは対照的に、letおよびconstキーワードは、ブロックステートメント内のローカルスコープの宣言をサポートします。

var x = 10
let y = 10
const z = 10
{
  x = 20
  let y = 20
  const z = 20
  {
    x = 30
    // x is in the global scope because of the 'var' keyword
    let y = 30
    // y is in the local scope because of the 'let' keyword
    const z = 30
    // z is in the local scope because of the 'const' keyword
    console.log(x) // 30
    console.log(y) // 30
    console.log(z) // 30
  }
  console.log(x) // 30
  console.log(y) // 20
  console.log(z) // 20
}

console.log(x) // 30
console.log(y) // 10
console.log(z) // 10
1
Dava

EcmaScript 5には主に2つのスコープ、 local scope および global scope がありますが、EcmaScript 6には主に3つのスコープ、ローカルスコープ、グローバルスコープ、および block scope という新しいスコープがあります。

ブロックの有効範囲の例は次のとおりです。

for ( let i = 0; i < 10; i++)
{
 statement1...
statement2...// inside this scope we can access the value of i, if we want to access the value of i outside for loop it will give undefined.
}
1
Vivek Mehta