最近、私は「JavaScript Advanced Programming 3」を読み直しており、学んだ知識のいくつかを記録するためにいくつかのブログを書くべきだと感じています。今日私が要約したいのは、JS実行環境と範囲です。
まず、実行環境について話しましょう
1。実行環境
本の概念である実行環境は、変数または関数がアクセスし、それぞれの動作を決定する他のデータを定義します。各実行環境には、それに関連付けられた変数オブジェクトがあります。環境で定義されているすべての変数と関数は、このオブジェクトに保存されます。このオブジェクトを書くときはこのオブジェクトにアクセスすることはできませんが、パーサーはデータを処理するときにバックグラウンドで使用します。
実行環境は概念であり、変数または関数が他のデータにアクセスする許可を持っているかを定義するメカニズムです
JavaScriptでは、実行可能ファイルJavaScriptコードが3つのタイプに分割されます。
1。グローバルコード、つまり、次のような関数にはないグローバルコード、JSファイル、HTMLページに埋め込まれたJSコードなど。
2。evalコード、つまり、eval()関数を使用して動的に実行されるJSコード。
3。関数コード、つまり、ユーザー定義関数の関数本文JSコード。
評価コードをスキップし、グローバルな実行環境と関数実行環境についてのみ話します。
1。グローバル環境:
グローバル環境は、最も周辺の実行環境です。グローバル実行環境は、ウィンドウオブジェクトと見なされます。したがって、すべてのグローバル変数と関数は、ウィンドウオブジェクトのプロパティと方法として作成されます。コードがブラウザにロードされると、グローバル実行環境が作成されます(グローバル実行環境は、Webページまたはブラウザを閉じるときにのみ破壊されます)。たとえば、ページで、JSコードが初めてロードされたときにグローバルな実行環境を作成します。
これが、閉鎖にメモリリークの不利な点がある理由でもあります。閉鎖の外部機能はグローバル環境として扱われるためです。したがって、それは破壊されず、記憶に保たれます。
2。関数実行環境
各機能には独自の実行環境があります。実行が関数に入ると、関数の実行環境が実行環境スタックの最上部にプッシュされ、実行権が取得されます。この関数が実行されると、その実行環境はスタックの上部から削除され、実行右は以前の実行環境に返されます。これは、ECMAScriptプログラムの実行フローです。
この方法で解釈することもできます。JavaScript関数が呼び出されると、関数は関数に対応する実行環境に入ります。別の関数が呼び出された場合、新しい実行環境が作成され、機能呼び出し中に実行プロセスがその環境にあります。呼び出された関数が戻ると、実行プロセスは元の実行環境に戻ります。したがって、JavaScriptコードを実行すると、実行環境スタックが形成されます。
関数が呼び出されると、関数のローカル環境が作成されます(関数内のコードが実行され、環境が破壊され、その中に保存されているすべての変数と関数定義も破壊されます)。
2-1定義期間
関数が定義されると、[[scope]]属性が作成されます。このオブジェクトは、オブジェクトのリストに対応します。リスト内のオブジェクトは、JavaScriptによって内部的にのみアクセスでき、構文を介してアクセスすることはできません。
(スコープは範囲を意味します。)
グローバル関数aを定義し、A関数がAの[[scope]]属性を作成します。この時点で、[[scope]]にはグローバルオブジェクト[グローバルオブジェクト]のみが含まれています。
A内で関数bを定義すると、関数Bは[[scope]]属性も作成します。 bの[[[scope]]属性には2つのオブジェクトが含まれています。1つはアクティブオブジェクトAのアクティブオブジェクトアクティベーションオブジェクト、もう1つはグローバルオブジェクトです。 Aのアクティブなオブジェクトは前にあり、グローバルオブジェクトは背面にあります。
要するに、関数の[スコープ]プロパティのオブジェクトリストの順序は、関数の前のレイヤーのアクティブ化オブジェクトであり、次に上層が最も外側のグローバルオブジェクトまでずっとあります。
サンプルコードは次のとおりです。Aには1つのスコープのみ、Bには2つのスコープがあります
//外部関数関数a(){var somevar; //内部関数関数b(){var somevar; }}2-2実行期間
関数が実行されると、関数の実行環境に入ります。まず、独自のアクティブオブジェクト[Activation Object](このオブジェクトには、この引数、ローカル変数(名前付きパラメーターを含む)、および変数オブジェクトのスコープチェーンが含まれます。次に、実行環境の範囲を[[スコープチェーン]]にコピーし、最終的にアクティブオブジェクトを[[スコープチェーン]]にプッシュします。実行環境へのアクセス許可を持つオブジェクト。
//最初のステップは、グローバルな実行環境を作成することです。グローバル実行コンテキストとグローバルアクティビティオブジェクト。 //ウィンドウオブジェクトのみを含むグローバル[[scope]]を定義します//グローバル定義変数と関数オブジェクトをスキャンします。 //プログラムは定義されているため、ChangeColor()はこの実行環境のどこでも実行できます。色も定義されていますが、その値は未定義です// 2番目のステップは「ブルー」var色= "blue"; //独自の関数changecolor()を指しません、{// 4番目のステップは、changecolorの実行環境に入ります// copy copy in copy of comping of and come offerned ofction and define functs and define functs、define scan scan scan scan別の色【未定義】およびスワップコラーfd fdは、swapcolors [[scope]]を作成し、アクティブなオブジェクトとグローバルアクティブオブジェクトをアクティブオブジェクトに追加し、この//アクティブオブジェクトがスコープチェーンにプッシュする//プログラムは、このエグゼクティブ環境のどこでも実行できます。別の色が定義されていますが、その値は未定義です// 5番目のその他のカラーの割り当て "red" var anothercolor = "red"; //割り当ては必要ありません。それは独自の関数を参照しますswapColors(){//ステップ7 SwapColorsの実行環境を入力し、そのアクティブなオブジェクトを作成します別の色、別の色、色のTempcolorの割り当て値は、スコープチェーンに沿って見られ、var tempcolor = Anothercolorを実行し続けます。 AnotherColor = color; color = tempcolor; } //ステップ6:SwapColorsを実行し、その実行環境SwapColors();} //ステップ3:ChangeColorを実行し、実行環境ChangeColor()を入力します。2-3アクセス識別子:
JSコードの実行中に識別子が発生すると、識別子の名前に基づいて実行コンテキスト(実行コンテキスト)のスコープチェーン(実行コンテキスト)で検索されます。スコープチェーンの最初のオブジェクト(関数のアクティベーションオブジェクト)から始まり、見つからない場合は、スコープチェーンの次のオブジェクトを検索し、識別子定義が見つかるまで繰り返します。検索の検索後にスコープ内の最後のオブジェクトが見つからない場合、つまりグローバルオブジェクト(グローバルオブジェクト)は、エラーがスローされ、未定義になります。
2。スコープ/スコープチェーン(スコープ/スコープチェーン)
環境でコードが実行されると、スコープチェーンが作成されます。スコープチェーンの目的は、実行環境へのアクセス許可を持つすべての変数と機能に秩序あるアクセスを確保することです。スコープチェーン全体は、ルールに従って異なる実行場所で可変オブジェクトによって構築されたリンクリストです。スコープチェーンのフロントエンドは、常に実行されているコードが配置されている環境内の変数オブジェクトです。
この環境が関数である場合、そのアクティベーションオブジェクトは可変オブジェクトとして使用されます。アクティブオブジェクトには、最初に1つの変数のみが含まれます。これは、関数内の引数オブジェクトです。スコープチェーンの次の変数オブジェクトは、関数のインクルージョン環境からのものであり、次の変数オブジェクトは次のインクルージョン環境から来ます。このようにして、それはグローバルな実行環境に続き、グローバル実行環境の変数オブジェクトは常にスコープチェーンの最後のオブジェクトです。
図に示されているように:
本の例:
var color = "blue"; function changecolor(){var anothercolor = "red";関数swapcolors(){var tempcolor = anothercolor; AnotherColor = color; color = tempcolor; // todo何か} swapcolors();} changecolor(); //ここでは、TempColorとAnocolorにアクセスできません。しかし、色にアクセスできます;アラート( "色は今"+色);上記の分析を通じて、内部環境はスコープチェーンを介してすべての外部環境にアクセスできることを知ることができますが、外部環境は内部環境の変数や機能にアクセスできません。
これらの環境は線形で秩序です。各環境は、スコープチェーンを上向きに検索して、変数と機能名を照会します。ただし、スコープチェーンを下向きに検索することにより、どの環境も別の実行環境に入ることはできません。
上記の例では、swapcolor()関数には、そのスコープチェーンには、swapcolor()変数オブジェクト、changecolor()変数オブジェクト、およびグローバルオブジェクトが含まれます。 SwapColor()のローカル環境は、独自の変数オブジェクトで変数と関数名の検索を開始します。見つからない場合は、Canhcolor Scopeチェーンを上向きに検索します。 。 。 。 。等々。ただし、ChangeColor()関数はSwapColorの変数にアクセスできません
黙示録:ローカル変数を使用して検索時間を短縮してみてください
1.ブロックレベルのスコープなし
C、C ++、およびJavaとは異なり、JavaScriptにはブロックレベルのスコープはありません。次のコードを見てください。
if(true){var myvar = "zhang san"; } alert(myvar); // Zhang Sanブロックレベルのスコープがある場合、MyVarに外部からアクセスできません。以下を見てください
for(var i = 0; i <10; i ++){console.log(i)} alert(i); // 10JavaやC#コードなどのブロックレベルのスコープを持つ言語の場合、私は変数の初期化されており、外部にアクセスすることはできません。私はforループ重量のみに存在するため、forループを実行した後、forのすべての変数が破壊されます。これはJavaScriptには当てはまりません。 forの変数宣言は、現在の実行環境に追加されます(ここにグローバルな実行環境があります)。したがって、forループが完了した後、ループの外側の実行環境に私が存在する変数がまだ存在します。したがって、10は出力されます。
2。変数を宣言します
変数がVARを使用して宣言されると、この変数は利用可能な最も近い環境に自動的に追加されます。関数の内部では、最も近い環境は関数のローカル変数です。変数が初期化されていない場合、変数はグローバル関数に自動的に追加されます。
コードは次のとおりです。
var name = "xiao ming";関数getName(){alert(name); //「未定義」var name = 'xiao huang';アラート(名前); // xiao huang} getname()ファーストネームが未定義なのはなぜですか?これは、JavaScriptパーサーが関数実行環境に入り、最初にVARと機能をスキャンするためです。
これは、実行環境の最上位にVARまたは関数[関数宣言]宣言を促進することと同等です。
言い換えれば、getName関数を入力すると、識別子検索メカニズムがVARを見つけ、名前はグローバル名ではなくローカル変数名です。これは、関数の名前が上部に宣伝されるためです。
上記のコードは次のように解析されます。
var name = "xiao ming";関数getName(){var name;アラート(名前); //「未定義」var name = 'xiao huang';アラート(名前); // xiao huang} getname()スコープチェーンを拡張します。
実行環境には2種類の種類しかありません。グローバルスコープと機能範囲ですが、スコープチェーンは何らかの形で拡張できます。一部のステートメントでは、一時的な変数オブジェクトをスコープチェーンの最上部に追加できるためです。
これが起こる2つの状況があります:
1。トライキャッチステートメントのキャッチブロック。
2。声明で。
上記はこの記事に関するすべてです。誰もがJavaScriptの実行環境と範囲を学び、理解することが役立つことを願っています。