[JS]実行コンテキスト-スコフ、スコフチェーン、外部環境参照


この文章.📕Core JavaScriptベースの記事です.

💡 スキャン


スコットランド?識別子の有効範囲
任意の境界Aの外部宣言変数は、Aの外部からアクセスしてもよいし、Aの内部からアクセスしてもよい.
Aの内部宣言の変数はAの内部からしかアクセスできません.
ES 5へのJavaScriptは、グローバルスペースを除き、関数のみでスキャンを生成します.
ES 6では、ブロックもスキャン境界を生じるため、他の言語と非常に類似している.
varとして宣言された変数にのみ機能せず、新しく生成されたletやconst、class、strict modeの関数宣言などの実行範囲にのみ作用します.
ES 6では、関数スキャンとブロックスキャンの両方を区別するために用語が使用される.
これらの「識別子の有効範囲」を内側から外側に順に検索し、範囲チェーン(scope chain)と呼ぶ.
それを可能にしたのがLexicalEnvironmentの2番目の収集資料OuterEnvironmentReferenceです.

ひょうじチェーン


outerEnvironmentReferenceは、現在呼び出す関数宣言時のLexicalEnvironmentを参照します.
ここで注目すべき部分は「宣言当時」です.
宣言動作が実際に発生する可能性のある時点は、呼び出しスタック内の実行コンテキストがアクティブな場合にのみ発生します.
宣言関数の動作自体は、すべてのコードが実行コンテキストがアクティブなときに実行されるため、コードにすぎません.
たとえば、A関数の内部にB関数を宣言し、B関数の内部にC関数を宣言します.
関数Cの外部環境は、関数BのLexicalEnvironmentを参照する.
関数BのLexicalEnvironmentのoutherEnvironmentReferenceは、関数B宣言時(A)のLexicalEnvironmentを再参照します.
このようにouterEnvironmentReferenceは「リンクリスト」形式です.
「宣言ポイントのLexicalEnvironment」を検索し続けると、最後にグローバルコンテキストのLexicalEnvironmentがあります.
各外部環境リファレンスは、最近の要素からのみ順次アクセスでき、他の順序でアクセスできません.
📌 整理する.
この構造特性により、複数のスキャンで同じ識別子が宣言された場合、スキャンチェーンで最初に発見された識別子に無条件にアクセスできます.

スキャンチェーンの例



上記のコードを実行すると、

結果は以下の通りです.
グローバルスペースでは、グローバルスキャンで生成された変数にのみアクセスできます.
outer関数の内部では、outerとグローバルscopeで生成された変数にアクセスできますが、inner scopeで生成された変数にはアクセスできません.
内層関数の内部では、internal、outer、グローバルscopeにアクセスできます.
しかし内関数内部[4]の第一線がundefinedの結果を出した原因は?
スコフ鎖上の変数が無条件に近づくわけではない.
上のコードの識別子aは、グローバル空間においても宣言され、内部関数においても宣言される.
内部関数からaにアクセスしようとする場合は、スキャンチェーン上の最初のパラメータ、すなわち内部スキャンのLexicalEnvironmentから検索を開始する必要があります.
内視鏡のLexicalEnvironmentに識別子が存在するため、さらなるスキャンチェーン探索を行わず、直ちに内視鏡Environment上のaに戻る.
上記の現象を変数非表示化(variableshadown)と呼ぶ.

クロムブラウザでのスキャン情報の表示


Chromeブラウザ環境では、開発者ツールのコンソールから、現在のコンテキスト以外のすべてのトップスキャン情報を簡単に表示できます.
var a = 1;
var outer = function () {
  var b = 2;
  var inner = function () {
    console.dir(inner);
  };
  inner();
};
outer();
確認の方法は以下の通りです.関数の内部に関数を出力します.console.dir() ?
コンソールで指定したJavaScriptオブジェクトのすべてのプロパティを表示して、開発者が簡単にオブジェクトのプロパティを取得できるようにします.

デバッガを使用すると、より正確な情報を表示できます.console.dir(...)部分をdebuggerに変更して運転
var a = 1;
var outer = function () {
  var b = 2;
  var inner = function () {
    debugger; <- !! 
  };
  inner();
};
outer();

グローバル変数とゾーン変数


上記の例では、グローバル変数は、グローバルscopeで宣言されたaとouterの2つです.
領域変数はouter関数内部宣言の内部と内部関数内部宣言のaの2つである.
すなわち,グローバル空間で宣言される変数はグローバル変数であり,関数内部で宣言される変数は無条件の領域変数である.
これまで、グローバル変数、領域変数は当然の受け入れと使用にすぎず、スコフに対して正確な理解があり、グローバル変数、領域変数の意義はさらに深いようだ.
グローバル変数をできるだけ減らすべき理由をより深く考えることができます.
実行コンテキストでは、this Bindingはthisによって指定されたオブジェクトを格納します.
私たちは次のページでこの問題について議論します.