まず、以下は範囲を説明する3つのコードです
// ==========例1 ============= var scope = 'global'; function fn(){alert(scope); var scope = 'local'; alert(scope);} fn(); //出力の結果?アラート(スコープ); //出力結果? // ===========例2 ============= var scope = 'global'; function fn(){alert(scope); scope = 'local'; alert(scope);} fn(); //出力の結果?アラート(スコープ); //出力結果? // ===========例3 =========== var scope = 'global'; function fn(scope){alert(scope); scope = 'local'; alert(scope);} fn(); //出力の結果?アラート(スコープ); //出力結果?これらの3つのコードにはわずかな違いしかありませんが、結果は完全に異なります。例1出力[未定義、ローカル、グローバル]、例2出力[グローバル、ローカル、ローカル]、例3出力[未定義、ローカル、グローバル]。正しく答えることができない場合は、JavaScriptの範囲特性をまだ理解していないことを意味します。
スコープとは何ですか?
誰かが尋ねるかもしれません:変数aの範囲は何ですか?後でもう一度尋ねました:機能の範囲は何ですか?変数と関数の範囲は何ですか?
まず、「スコープ」の意味を見てみましょう。 「スコープ」が分解されると、「機能」と「ドメイン」を意味します
スコープは、変数と関数のアクセス可能な範囲、または変数または関数が機能する領域です。
1.JavaScript関数のスコープ:
関数内の領域は関数の範囲であり、変数と関数の両方がこの領域の操作にアクセスできます。最も外側の関数の外側の領域はグローバルスコープと呼ばれ、関数内の領域はローカルスコープと呼ばれます。
2。JavaScript変数の範囲:
変数がソースコードにある領域では、この変数の範囲があり、この領域内で変数にアクセスして動作することができます。グローバルスコープで定義されている変数はグローバル変数と呼ばれ、関数で定義される変数はローカル変数と呼ばれます。
簡単に理解するために、JSソースコードは、関数{}によってブロックの領域に分割されます。これらの領域がアイデンティティを変更する場合、それらは特定の関数または特定の変数の範囲です。変数の範囲と関数の範囲は、ソースコードの同じ領域を参照する場合があります。
スコープチェーン
スコープチェーンは、JavaScript内の可変および関数検索メカニズムです。変数と関数の範囲、つまり範囲を決定します。スコープチェーンの原則を理解すると、前の記事の3つの例を理解することができます。そうすれば、理由と理由を知ることができます。
Scope Chainは、ECMAScript-262ドキュメントの概念です。 JavaScriptエンジンは、ECMAScript-262ドキュメントに従って実装されています。 JavaScriptエンジンの実用的な原則を理解することは、JavaScriptの特性を理解することを助長しますが、ほとんどのJSプログラマーは非常に根本的なテクノロジーを理解していません。したがって、ECMAScript-262ドキュメントを読むとき、JavaScriptエンジンの作業原理をシミュレートする直感的な方法を持つことができます。
この記事では、1999年にECMAScript-262-3thの第3版を通じて範囲チェーンを形成する原則について説明し、実行環境、可変オブジェクト、アクティブオブジェクト、引数オブジェクト、スコープチェーンなどのいくつかの概念を紹介します。違いは、可変オブジェクトやアクティブオブジェクトなどの概念がキャンセルされ、語彙環境や環境記録などの新しい概念が導入されたため、2つのバージョンの概念を混同しないでください。
1.解放コンテキスト
実行コンテキストも実行コンテキストに翻訳されます。パーサーがECMAScriptの実行可能コードに入ると、パーサーは実行環境に入ります。アクティブな実行環境は、論理スタックを形成します。この論理スタックの上部にある実行環境は、現在の実行環境です。
注:ECMAScript、グローバル、機能、および評価には、3種類の実行可能コードがあります。グローバル環境はグローバル実行可能コードであり、関数は機能実行可能コードです。ロジックスタックは特別なデータストレージ形式で、「最初の出入りとその後」を特徴としています。データの追加は最初にロジックスタックの上部に押し込まれ、データの削除を上から削除する必要があります。
可変オブジェクト、アクティブオブジェクト、および引数オブジェクト
各実行環境には、それに関連付けられた変数オブジェクトがあります。パーサーが実行環境に入ると、変数オブジェクトが作成され、現在の実行環境で宣言された変数と関数への参照を保持します。
可変オブジェクトは抽象的な概念です。異なる実行環境では、可変オブジェクトには異なるアイデンティティがあります。パーサーが実行環境に入る前に、グローバルオブジェクトが作成されます。パーサーがグローバル実行環境に入ると、グローバルオブジェクトは変数オブジェクトとして機能します。パーサーが関数に入ると、アクティブオブジェクトが可変オブジェクトとして作成されます。
2。パーサーがコードを処理する2つの段階
私たちは皆、JavaScriptパーサーがコードを1つずつ解析することを知っています、それはマットですか?これには、パーサーがコードを処理するときに2つの段階が含まれ、コードを解析してコードを実行します。
パーサーが実行環境に入ると、変数オブジェクトは実行環境で宣言された変数と関数をそのプロパティとして追加します。つまり、宣言の前に変数と関数が利用可能であり、変数値は定義されていません。これが、変数と関数宣言の促進の理由です(巻き上げ)。同時に、スコープチェーンとこれが決定されます。このプロセスは、一般的に前包帯として知られている解析段階です。次に、パーサーはコードの実行を開始し、対応する値への参照を変数に追加し、実行結果を取得します。このプロセスは実行段階です。
2つのおいしい栗に名前を付けましょう:
var a = 123; var b = "abc"; function c(){alert('11 ');}上記のグローバル環境でコードの解析と実行の後、グローバルオブジェクトは可変オブジェクトとして使用され、次のデータが保存されます。
関数testfn(a){var b = "123"; function c(){alert( "abc"); }} testfn(10);パーサーが関数実行環境に入ると、アクティブオブジェクトが可変オブジェクトとして作成されます。アクティブオブジェクトは、引数オブジェクトも作成します。引数オブジェクトは、パラメーターを保存するためのパラメーターセットです。これが、関数を書くときに引数[0]などを使用できる理由です。
3。スコープチェーン
各実行環境には、それに関連するスコープチェーンがあります。パーサーが実行環境に入るときに定義されます。スコープチェーンは、各変数オブジェクトの変数と関数を取得するために使用されるオブジェクトリストです。これにより、実行環境がどの変数と機能にアクセスする権利を持つことができます。たとえば、栗です。
var a = '123'; function testfn(b){var c = 'abc';関数testfn2(){var d = 'efg';アラート(a); } testfn2();} testfn(10);変数Aはtestfn2で宣言されていません。 TestFN2がグローバル変数Aを呼び出すことができるのはなぜですか?プロセス全体はどのように起こりましたか?下の写真をご覧ください。
パーサーがグローバルな実行環境に入ると、変数と関数は、それらを呼び出すときにグローバルオブジェクトにのみ見つかります。
パーサーがtestFN関数実行環境に入ると、関数の内部プロパティ[[scope]]が最初にグローバルオブジェクトに埋められ、次にtestFNアクティブオブジェクトがグローバルオブジェクトに追加されてスコープチェーンを形成します。
パーサーがtestFN2関数実行環境に入ると、関数[[scope]]の内部プロパティが親スコープチェーンに最初に埋められ、次に現在のtestfn2アクティブオブジェクトがスコープチェーンのフロントエンドに追加され、新しいスコープチェーンを形成します。
testFN2が変数Aを呼び出す場合、現在のTESTFN2アクティブオブジェクトで最初に検索します。発見されていない場合は、スコープチェーンを上方に進みます。見つからない場合は、スコープチェーンを調べます。発見されていない場合は、最後のグローバルオブジェクトで見つかるまでスコープチェーンを調べます。そうしないと、エラーが報告されます。したがって、外部環境の変数を関数内で呼び出すことができ、外部環境の変数を関数内で呼び出すことはできません。これが範囲の特性の原則です。