ホームページ ウェブフロントエンド jsチュートリアル JavaScript スコープとスコープchain_javascript スキルの詳細な分析

JavaScript スコープとスコープchain_javascript スキルの詳細な分析

May 16, 2016 pm 05:10 PM
javascript 範囲 スコープチェーン

スコープは JavaScript の最も重要な概念の 1 つです。JavaScript をよく学びたい場合は、JavaScript のスコープとスコープ チェーンの動作原理を理解する必要があります。今日の記事では、JavaScript のスコープとスコープ チェーンについて簡単に紹介し、誰もが JavaScript をより良く学習できるようにしたいと考えています。

JavaScript スコープ

どのプログラミング言語にもスコープの概念があります。簡単に言えば、スコープは変数と関数のアクセス可能な範囲です。つまり、スコープは変数と関数の可視性とライフサイクルを制御します。 JavaScript には、グローバル スコープとローカル スコープの 2 種類の変数スコープがあります。

1. グローバル スコープ

コード内のどこからでもアクセスできるオブジェクトにはグローバル スコープがあります。一般に、グローバル スコープを持つ状況がいくつかあります。

(1) 最も外側の関数とその外側で定義された変数はグローバル スコープを持ちます。例:


コードをコピー コードは次のとおりです:
var authorName="Mountainside Brook";
function doSomething(){
var blogName="";
function innerSay(){
alert(blogName);
innerSay();
alert(authorName) //Mountainside Stream
alert(blogName); ; //
innerSay() //スクリプト エラー


(2) 定義されておらず、値が直接割り当てられていないすべての変数は、次のように自動的にグローバル スコープを持つように宣言されます。


コードをコピーします
コードは次のとおりです:function doSomething(){ var authorName=" Shanbian Xiao Stream"; blogName="";
alert(authorName);
}
alert(blogName); //
alert(authorName); // スクリプト エラー


変数 blogName にはグローバル スコープがありますが、関数の外部から authorName にアクセスすることはできません。

(3) すべてのウィンドウ オブジェクト プロパティにはグローバル スコープがあります
通常、ウィンドウ オブジェクトの組み込みプロパティには、window.name、window.location、window.top などのグローバル スコープがあります。

2. ローカルスコープ

グローバル スコープとは対照的に、ローカル スコープは通常、固定されたコード フラグメント内でのみアクセスできます。最も一般的なものは関数内にあるため、場所によっては、このスコープを関数スコープと呼んでいる場合があります。次のコードの、blogName および関数 innerSay はローカル スコープのみを持ちます。

コードをコピー

コードは次のとおりです。function doSomething(){ var blogName=" "; 関数 innerSay(){
alert(ブログ名)
}
alert(ブログ名); >innerSay( ); //スクリプト エラー


スコープ チェーン

JavaScript では、関数もオブジェクトです。実際、JavaScript 内のすべてのものはオブジェクトです。関数オブジェクトには、他のオブジェクトと同様に、コードを通じてアクセスできるプロパティと、JavaScript エンジンのみがアクセスできる一連の内部プロパティがあります。内部プロパティの 1 つは [[Scope]] で、ECMA-262 標準第 3 版で定義されています。この内部プロパティには、関数が作成されるスコープ内のオブジェクトのコレクションが含まれます。このコレクションは関数のスコープ チェーンと呼ばれます。 、関数がどのデータにアクセスできるかを決定します。

関数が作成されると、そのスコープ チェーンには、関数が作成されたスコープ内でアクセス可能なデータ オブジェクトが設定されます。たとえば、次の関数を定義します:


コードをコピーします

コードは次のとおりです:

function add(num1, num2) { var sum = num1 num2 } 関数 add が作成されると、グローバル オブジェクトが入力されます。次の図に示すように、グローバル オブジェクトにはすべてのグローバル変数が含まれています (注: この図はすべての変数の一部のみを示しています):




関数 add のスコープは実行時に使用されます。たとえば、次のコードを実行します。



コード
をコピーします。 コードは次のとおりです。


var total = add(5, 10);
この関数が実行されると、「実行コンテキスト」と呼ばれる内部オブジェクトが作成され、関数が実行されるときの環境を定義します。各ランタイム コンテキストには、識別子解決のための独自のスコープ チェーンがあり、ランタイム コンテキストが作成されると、そのスコープ チェーンは、現在実行中の関数の [[Scope]] に含まれるオブジェクトに初期化されます。

値は、関数内に出現する順序でランタイム コンテキストのスコープ チェーンにコピーされます。これらは一緒に「アクティベーション オブジェクト」と呼ばれる新しいオブジェクトを形成します。このオブジェクトには、すべてのローカル変数、名前付きパラメータ、パラメータ コレクションが含まれており、実行時にこのオブジェクトがスコープ チェーンのフロント エンドにプッシュされます。コンテキストが破棄されると、アクティブなオブジェクトも破棄されます。新しいスコープ チェーンは次のとおりです:

関数の実行中に変数が見つからない場合、識別子の解析プロセスを経て、データを取得して保存する場所が決定されます。このプロセスはスコープ チェーンの先頭、つまりアクティブなオブジェクトから開始され、同じ名前の識別子が見つかった場合は、その識別子に対応する変数を使用します。見つからない場合は、続行します。スコープチェーン内の次のオブジェクトを検索します。 If 検索後にオブジェクトが見つからない場合、識別子は未定義とみなされます。関数実行時には、各識別子に対してこのような検索処理が行われます。

スコープチェーンとコードの最適化

スコープ チェーンの構造から、識別子がランタイム コンテキストのスコープ チェーンの深いところにあるほど、読み取りと書き込みの速度が遅くなることがわかります。上の図に示すように、グローバル変数は常にランタイム コンテキスト スコープ チェーンの最後に存在するため、識別子の解決中にグローバル変数を見つけるのが最も遅くなります。したがって、コードを記述するときは、グローバル変数の使用をできるだけ少なくし、ローカル変数をできるだけ使用する必要があります。経験則としては、クロススコープ オブジェクトが複数回参照される場合は、使用する前にローカル変数に格納します。たとえば、次のコード:

コードをコピー コードは次のとおりです:

function changeColor (){

document.getElementById("btnChange").onclick=function(){

document.getElementById("targetCanvas").style.backgroundColor="red";

};

}


この関数は、グローバル変数ドキュメントを 2 回参照し、変数を見つけるには、グローバル オブジェクトで最終的に見つかるまでスコープ チェーン全体をたどる必要があります。このコードは次のように書き換えることができます:
コードをコピー コードは次のとおりです:

関数changeColor() {

var doc=ドキュメント

doc.getElementById("btnChange").onclick=function(){

doc.getElementById("targetCanvas").style.backgroundColor="red";

};

}


このコードは比較的単純で、書き換えても大きなパフォーマンスの向上は見られませんが、プログラム内に繰り返しアクセスされるグローバル変数が多数ある場合、書き換えられたコードのパフォーマンスは大幅に向上します。

スコープチェーンの変更

対応するランタイム コンテキストは関数が実行されるたびに一意であるため、同じ関数を複数回呼び出すと、関数の実行が完了すると複数のランタイム コンテキストが作成されます。各ランタイム コンテキストはスコープ チェーンに関連付けられます。通常、ランタイム コンテキストの実行中、そのスコープ チェーンは with ステートメントと catch ステートメントによってのみ影響を受けます。

with ステートメントは、オブジェクトを使用してコードを繰り返し記述することを避けるためのショートカット方法です。例:

コードをコピー コードは次のとおりです。

function initUI(){

with(ドキュメント){

var bd=body,

links=getElementsByTagName("a"),

i=0、

len=リンクの長さ

while(i

更新(リンク[i ]);

}

getElementById("btnInit").onclick=function(){

doSomething()

};

}

}



ここで width ステートメントは、ドキュメントを複数回記述することを避けるために使用されており、効率的であるように見えますが、実際にはパフォーマンスの問題が発生します。

コードが with ステートメントまで実行されると、ランタイム コンテキストのスコープ チェーンが一時的に変更されます。パラメーターで指定されたオブジェクトのすべてのプロパティを含む新しい可変オブジェクトが作成されます。このオブジェクトはスコープ チェーンの先頭にプッシュされます。つまり、関数のすべてのローカル変数が 2 番目のスコープ チェーン オブジェクト内にあるため、アクセスコストが高くなります。以下に示すように:


したがって、この例では、ドキュメントをローカル変数に保存するだけでパフォーマンスが向上するため、プログラム内で with ステートメントを使用することは避けてください。

スコープ チェーンを変更するもう 1 つの点は、try-catch ステートメント内の catch ステートメントです。 try コード ブロックでエラーが発生すると、実行プロセスは catch ステートメントにジャンプし、その後、例外オブジェクトが可変オブジェクトにプッシュされ、スコープの先頭に配置されます。 catch ブロック内では、関数のすべてのローカル変数が 2 番目のスコープ チェーン オブジェクトに配置されます。サンプルコード:

コードをコピー コードは次のとおりです:

try{

doSomething()

}キャッチ(例){

alert(ex.message); // ここでスコープチェーンが変更されます

}


catch ステートメントが実行されると、スコープ チェーンは以前の状態に戻ることに注意してください。 try-catch ステートメントはコードのデバッグや例外処理に非常に役立つため、完全に回避することはお勧めできません。コードを最適化することで、catch ステートメントのパフォーマンスへの影響を軽減できます。良いパターンは、エラー処理を関数に委任することです。例:
コードをコピー コードは次のとおりです:

試してください{

doSomething()

}キャッチ(例){

handleError(ex); //プロセッサメソッドに委任します

}


最適化されたコードでは、catch 句で実行されるコードは handleError メソッドだけです。この関数は例外オブジェクトをパラメータとして受け取るため、エラーをより柔軟かつ均一に処理できます。実行されるステートメントは 1 つだけであり、ローカル変数にはアクセスされないため、スコープ チェーンの一時的な変更はコードのパフォーマンスに影響しません。

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

C言語でのtypedef構造体の使い方 C言語でのtypedef構造体の使い方 May 09, 2024 am 10:15 AM

typedef struct は、構造体の使用を簡素化するために構造体型のエイリアスを作成するために C 言語で使用されます。構造体の別名を指定することで、新しいデータ型を既存の構造体に別名付けします。利点としては、可読性の向上、コードの再利用、型チェックなどが挙げられます。注: エイリアスを使用する前に構造体を定義する必要があります。エイリアスはプログラム内で一意であり、宣言されているスコープ内でのみ有効である必要があります。

Javaで期待される変数を解決する方法 Javaで期待される変数を解決する方法 May 07, 2024 am 02:48 AM

Java における変数の期待値の例外は、変数の初期化、null 値の使用、およびローカル変数のスコープの認識によって解決できます。

JSのクロージャーの長所と短所 JSのクロージャーの長所と短所 May 10, 2024 am 04:39 AM

JavaScript クロージャーの利点には、変数スコープの維持、モジュール化コードの有効化、遅延実行、およびイベント処理が含まれますが、欠点としては、メモリ リーク、複雑さの増加、パフォーマンスのオーバーヘッド、およびスコープ チェーンの影響が挙げられます。

C++ で include は何を意味しますか C++ で include は何を意味しますか May 09, 2024 am 01:45 AM

C++ の #include プリプロセッサ ディレクティブは、外部ソース ファイルの内容を現在のソース ファイルに挿入し、その内容を現在のソース ファイル内の対応する場所にコピーします。主に、コード内で必要な宣言を含むヘッダー ファイルをインクルードするために使用されます。たとえば、標準入出力関数を組み込むための #include <iostream> などです。

C++ スマート ポインター: ライフサイクルの包括的な分析 C++ スマート ポインター: ライフサイクルの包括的な分析 May 09, 2024 am 11:06 AM

C++ スマート ポインターのライフ サイクル: 作成: スマート ポインターは、メモリが割り当てられるときに作成されます。所有権の譲渡: 移動操作を通じて所有権を譲渡します。リリース: スマート ポインターがスコープ外に出るか、明示的に解放されると、メモリが解放されます。オブジェクトの破壊: ポイントされたオブジェクトが破壊されると、スマート ポインターは無効なポインターになります。

C++ での関数の定義と呼び出しはネストできますか? C++ での関数の定義と呼び出しはネストできますか? May 06, 2024 pm 06:36 PM

できる。 C++ では、ネストされた関数の定義と呼び出しが可能です。外部関数は組み込み関数を定義でき、内部関数はスコープ内で直接呼び出すことができます。ネストされた関数により、カプセル化、再利用性、スコープ制御が強化されます。ただし、内部関数は外部関数のローカル変数に直接アクセスすることはできず、戻り値の型は外部関数の宣言と一致している必要があります。内部関数は自己再帰的ではありません。

Vueのletとvarの違い Vueのletとvarの違い May 08, 2024 pm 04:21 PM

Vue では、let と var の間で変数を宣言するときのスコープに違いがあります。 スコープ: var にはグローバル スコープがあり、let にはブロック レベルのスコープがあります。ブロックレベルのスコープ: var はブロックレベルのスコープを作成しません。let はブロックレベルのスコープを作成します。再宣言: var は同じスコープ内の変数の再宣言を許可しますが、let は許可しません。

js の this が指す状況がいくつかあります。 js の this が指す状況がいくつかあります。 May 06, 2024 pm 02:03 PM

JavaScript では、this のポインティング タイプには、1. グローバル オブジェクト、2. 関数呼び出し、4. イベント ハンドラー、5. アロー関数 (this の外側の継承) が含まれます。さらに、bind()、call()、および apply() メソッドを使用して、これが何を指すかを明示的に設定できます。

See all articles