各プログラミング言語では、その変数には特定の有効な範囲があります。この範囲を超えた後、変数は無効になります。これが変数の範囲です。数学的な観点から、それは独立変数の領域です。
スコープは、変数のアクセス可能な範囲です。つまり、スコープは変数と関数の可視性とライフサイクルを制御します。 JavaScriptでは、オブジェクトと関数も変数であり、変数は、その関数本体と任意の関数本体を宣言する任意の関数本体内で定義されます。
1。静的範囲と動的範囲
静的スコープ
つまり、宣言の範囲は、字句範囲としても知られているプログラム本体に基づいてコンパイル時に決定されることを意味します。ほとんどの最新のプログラミング言語は静的な範囲ルールを採用しており、JavaScriptはこの範囲を採用しています。
静的スコープを使用する言語では、最も内側のネストされたスコープルールは基本的に次のとおりです。宣言によって導入された識別子は、宣言が位置する範囲と、内部にネストされた別の宣言でカバーされない限り、内部にネストされた各スコープにも表示されます。
特定の識別子によって参照されるオブジェクトを見つけるために、それは現在の最も内側の範囲で見つける必要があります。宣言が見つかった場合、識別子によって参照されるオブジェクトが見つかります。それ以外の場合は、直接の外側スコープで検索し、プログラムの最も外側の営巣レベル、つまりグローバルオブジェクト宣言が配置されている範囲に到達するまで外側のスコープをチェックし続けます。すべてのレベルで宣言が見つからない場合、プログラムにはエラーがあります。次のように:
function cha(){var name = "xiao;" function chb(){function chc(){console.log(name); }}}最初に、関数はchb()から名前の定義を検索し、次にレイヤーごとにレイヤーを検索し続けます。最後に、名前の定義はCha()にあります。発見されていない場合、エラーが報告されます。
2。動的範囲
動的にスコープされた言語では、プログラムの変数によって参照されるオブジェクトは、プログラムの実行中にプログラムの制御フロー情報に基づいて決定されます。
2。JavaScriptの範囲
JavaScriptには2つのスコープがあります。つまり、グローバルスコープとローカルスコープです。
1。グローバル範囲
コードのどこにでも定義があります。 HTMLページにネストされたJSコードの一部でグローバル変数が定義されている場合でも、参照されるJSファイルに変数にアクセスできます。これは、グローバル変数に汚染を引き起こす可能性が非常に高いです。
次の3つのケースの変数は、グローバル変数と見なされます
(1)最も外側の関数と最も外側の変数にはグローバルな範囲があります
(2)定義なしに直接割り当てられた変数は、グローバルな範囲を持つと自動的に宣言されます
(3)すべてのウィンドウオブジェクトのプロパティにはグローバルスコープがあります
2。ローカルスコープ
通常、ローカルスコープは、関数内の変数(関数範囲)などの固定コードスニペットでのみアクセスできます。
var name = "xuxiaoping"; function echoname(){var firstname = "xu"; // local scope secondname = "xiao"; // global scope function echechofirstname(){console.log(first name); // xu} console.log(secondName); return echofirstname;} console.log(name); // global scope var f = echoname(); f(); console.log(firstName); console.log(secondName);結果は次のとおりです。
xuxiaoping
シャオ
Xu //内側関数は、外部関数の変数にアクセスできます
控えめに//関数の内部変数に関数の外側にアクセスできません
シャオ
JavaScriptは、グローバル変数をウィンドウオブジェクトに接続し、ウィンドウオブジェクトのプロパティになります。
3。関数範囲
ブロックレベルの範囲:ブレース内の一連のステートメントはブロックに属し、これで定義されているすべての変数はコードブロックの外側に見えません。ほとんどのCクラス言語には、ブロックレベルのスコープがあります。
ただし、JavaScriptの重要な機能は、ブロックレベルのスコープがないことです。
function echoi(){for(var i = 0; i <10; i ++){; // console.log(i); } if(true){var str = "hello"; } console.log(i); console.log(str);} echoi();出力の結果は次のとおりです。
10
こんにちは
声明の外側(または、場合)の外側では、ブロックで定義した変数にまだアクセスできることがわかります。つまり、JavaScriptはブロックレベルのスコープをサポートせず、関数スコープのみをサポートし、関数のどこでも定義されている変数はその関数のどこにでも表示されます。最初からCとJavaを学ぶ人として、これは適応するのが少し難しいです。私のテストによると、PHPにも同じことが言えます。
もちろん、JavaScriptの閉鎖特性を使用して、ブロックレベルのスコープをシミュレートできます
function echoi(){(function(){for(var i = 0; i <10; i ++){; // console.log(i);}})(); if(true){var str = "hello"; } console.log(i); console.log(str);} echoi();結果は次のとおりです
これにより、変数の定義が分離されます。 JSでは、競合の命名を防ぐために、グローバル変数とグローバル機能を可能な限り回避する必要があるため、この種の閉鎖は多くの点で使用されます。
4。JavaScript変数ライフサイクル
JavaScript変数ライフサイクルは、宣言されたときに初期化されます。
関数が実行された後、ローカル変数は破壊されます。
ページが閉じた後、グローバル変数は破壊されます。
3。JavaScriptスコープチェーン
チェーンのように見えますが、おそらくデータ構造のリンクリストと組み合わせることができます。
JavaScriptでは、関数はオブジェクトですが、実際、JavaScriptのすべてはオブジェクトです。関数オブジェクトは、他のオブジェクトと同様に、コードとJavaScriptエンジンのみにアクセスできる一連の内部プロパティを介してアクセスできるプロパティを持っています。内部プロパティの1つは[[[Scope]]で、ECMA-262標準の第3版で定義されています。この内部プロパティには、関数によって作成されたスコープ内のオブジェクトのコレクションが含まれています。このコレクションは、関数のスコープチェーンと呼ばれ、関数によってアクセスできるデータを決定します。
関数が作成されると、そのスコープチェーンには、関数の範囲でアクセス可能なデータオブジェクトが入力されます。たとえば、次のような関数を定義します。
関数add(num1、num2){var sum = num1 + num2; return sum;}関数追加が作成されると、下の図に示すように、すべてのグローバル変数を含むスコープチェーンにグローバルオブジェクトが入力されます(注:写真はすべての変数の一部のみを提供します):
機能追加の範囲は、実行中に使用されます。たとえば、次のコードを実行します。
var total = add(5,10);
この関数を実行すると、「実行コンテキスト」と呼ばれる内部オブジェクトが作成されます。ランタイムコンテキストは、関数が実行される環境を定義します。各ランタイムコンテキストには、識別子解析用の独自のスコープチェーンがあります。ランタイムコンテキストが作成されると、そのスコープチェーンは、現在の実行機能の[[scope]]に含まれるオブジェクトとして初期化されます。
これらの値は、関数に表示される順序でランタイムコンテキストのスコープチェーンにコピーされます。それらは、パラメーター、パラメーターセット、この関数という名前のすべてのローカル変数を含む「アクティブ化オブジェクト」と呼ばれる新しいオブジェクトを形成します。このオブジェクトは、スコープチェーンのフロントエンドに押し込まれます。実行中のコンテキストが破壊されると、アクティブオブジェクトが破壊されます。新しいスコープチェーンを以下の図に示します。
関数の実行中、変数に遭遇するたびに、識別子解析プロセスが渡され、データを取得して保存する場所を決定します。このプロセスは、スコープチェーンのヘッドから始まります。つまり、アクティブオブジェクトから同じ名前の識別子を検索します。見つかった場合は、この識別子に対応する変数を使用します。発見されていない場合は、スコープチェーン内の次のオブジェクトを検索し続けます。検索後にすべてのオブジェクトが見つからない場合、識別子は未定義と見なされます。関数の実行中、各識別子はそのような検索プロセスを通過する必要があります。
4.スコープチェーンとコードの最適化
スコープチェーンの構造から、ランタイムコンテキストのスコープチェーンでは、識別子が深くなるほど、読み取り速度が遅くなることがわかります。上の図に示すように、ランタイム中にコンテキストスコープチェーンの最後にグローバル変数が常に存在するため、識別子を解析するときにグローバル変数を見つけるのは最も遅いです。したがって、コードを作成するときは、グローバル変数をできるだけ使用しなく、できるだけローカル変数を使用するようにしてください。適切な経験則は、クロススコープオブジェクトが複数回参照されている場合、使用前にローカル変数に保存することです。たとえば、次のコード:
function changecolor(){document.getElementById( "btnChange")。onClick = function(){document.getElementById( "TargetCanvas")。style.backgroundcolor = "red"; };}この関数は、グローバル変数ドキュメントを2回参照します。変数は、グローバルオブジェクトに最終的に見つかるまで、スコープチェーン全体を通して検索する必要があります。このコードは次のように書き換えることができます。
function changecolor(){var doc = document; doc.getElementById( "btnChange")。onClick = function(){doc.getElementById( "TargetCanvas")。style.backgroundcolor = "red"; };}このコードは比較的単純であり、書き換え後に大規模なパフォーマンスの改善を示しませんが、プログラム内の多数のグローバル変数に繰り返しアクセスされると、書き換え後のコードのパフォーマンスが大幅に改善されます。
5。変更スコープチェーンを使用します
対応するランタイムコンテキストは、数値が実行されるたびに一意であるため、同じ関数を複数回呼び出すと、複数のランタイムコンテキストが作成されます。関数が実行されると、実行コンテキストが破壊されます。各ランタイムコンテキストは、スコープチェーンに関連付けられています。一般的に言えば、実行中のコンテキスト中に、そのスコープチェーンは、withステートメントとCatchステートメントのみの影響を受けます。
withステートメントは、重複コードの作成を避けるためにオブジェクトを適用する簡単な方法です。例えば:
function initui(){with(document){var bd = body、links = getelementsbytagname( "a")、i = 0、len = links.length; while(i <len){update(links [i ++]); } getElementById( "btninit")。onclick = function(){dosomething(); }; }}ここで幅のステートメントを使用して、ドキュメントを複数回記述しないようにしますが、これはより効率的に見えますが、実際にはパフォーマンスの問題が発生します。
コードがステートメントで実行されると、ランタイムコンテキストのスコープチェーンが一時的に変更されます。パラメーターで指定されたオブジェクトのすべてのプロパティを含む新しい可変オブジェクトが作成されます。このオブジェクトはスコープチェーンのヘッドに押し込まれます。つまり、関数のすべてのローカル変数が2番目のスコープチェーンオブジェクトにあるため、アクセスはより高価になります。下の図に示すように:
したがって、プログラムでは声明を避ける必要があります。この例では、ドキュメントをローカル変数に保存するだけでパフォーマンスを向上させることができます。
要約します
1.変数の範囲は、変数の範囲が有効な場合です。
2。変数のスコープチェーンは、作成されたスコープ内のオブジェクトのコレクションです。
上記はこの記事に関するものです。誰もがJavaScriptプログラミングを学ぶことが役立つことを願っています。