ホームページ >ウェブフロントエンド >jsチュートリアル >JavaScript スコープの使用の概要chain_javascript のヒント

JavaScript スコープの使用の概要chain_javascript のヒント

WBOY
WBOYオリジナル
2016-05-16 17:24:091047ブラウズ

私は以前、JavaScript クロージャとは何ですか? についてクロージャの理解について記事を書きました。これは非常に明確で、クロージャの理由を簡単に理解できると思います。私はチェーンとアクティブ オブジェクトだけがクロージャを本当に理解できると皆が言いました。その後、会社の同僚とコミュニケーションを取ったときに、スコープと実行環境が実際に非常に重要であることがわかりました。これらは JavaScript クロージャを理解するのに非常に役立つので、スコープと実行環境についての記事を書きました。

範囲

スコープは、変数と関数のアクセス可能なスコープであり、変数と関数の可視性とライフサイクルを制御します。JavaScript では、変数のスコープにはグローバル スコープとローカル スコープがあります。

一部の C に似たプログラミング言語では、中括弧内の各コードには独自のスコープがあり、変数は宣言されているコード セグメントの外では見えません。 JavaScript には、ブロック レベルのスコープはなく、関数レベルのスコープしかありません。変数は、宣言されている関数本体とサブ関数内で認識されます。

関数内で宣言されていないか、var なしで宣言されている変数はグローバル変数です。ウィンドウ オブジェクトのすべてのプロパティは、コード内のどこからでもアクセスできます。変数はローカル変数であり、関数本体内でのみ使用できます。関数のパラメーターは var を使用しませんが、それでもローカル変数です。

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

var a=3;
function fn(b){ //ローカル変数
var e=d; / /親関数のローカル変数は子関数から参照できます alert(i);/ /3、for ループ内で宣言されます。ループの外側の関数にはまだ表示されており、ブロックスコープ
はありません



JavaScript にはブロック スコープがないことを理解していれば、初心者が混乱しやすいもう 1 つの点は、JavaScript 変数にはさまざまな名前が存在することです。私が話しているのは 1 つのことです。JavaScript は解釈および実行されますが、実際に解釈および実行される前に、JavaScript インタープリターがコードを事前に解析し、変数と関数の宣言を解釈します。これは、関数宣言ステートメントの前に関数を呼び出すことができることを意味します。これはほとんどの人に共通ですが、変数の および 解析は一見すると奇妙に見えるかもしれません




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


console.log(a); //unknown var a=3; console.log( a); //3 console .log(b); //Uncaught ReferenceError: b が定義されていません 上記のコードの var a=3; の宣言部分は、実行前に -parsed (ただし、代入ステートメントは実行されません) なので、代入ステートメントを実行した後、初めてエラーが発生せずに未定義になります。上記のコードの最後の文を削除しても、同じになります。次のコードのように効果があります。



コードをコピー

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

var a;
console.log(a); //未定義
a=3;
console.log(a); >
しかし
これだけであれば、JavaScript のスコープの問題は非常に単純になりますが、関数のサブ関数によって引き起こされる問題により、スコープは単純ではなくなります。偉人がステージに登場します - 実行環境またはランタイム コンテキスト (良い人): 実行コンテキストは、変数または関数がアクセスできる他のデータを定義し、それぞれの動作を決定します。各実行環境には変数オブジェクト (VO) が関連付けられており、実行環境で定義されたすべての変数と関数は、データを処理するときにこの内部オブジェクトにアクセスします。

グローバル実行環境は、Web ブラウザーではウィンドウ オブジェクトであるため、すべてのグローバル変数と関数はウィンドウ オブジェクトの属性と増幅として作成されます。各関数には独自の実行環境があります。実行フローが関数に入ると、関数環境は関数スタックにプッシュされ、実行環境はスタックからポップされて、すべての情報が破棄されます。その後、変数と関数の定義は破棄され、アプリケーションが終了する (ブラウザが閉じる) まで、制御は前の実行環境に戻ります。

スコープチェーン

環境内でコードが実行されると、実行環境がアクセスできる変数と関数に順序よくアクセスできるように、変数オブジェクトのスコープ チェーン (sc) が作成されます。スコープ内の最初のオブジェクトは常に、コードが現在実行されている環境の変数オブジェクト (VO) です

コードをコピー コードは次のとおりです。function a(x,y){
var b=x y;
return b;
}



関数 a が作成されると、そのスコープ チェーンはすべてのグローバル変数を含むグローバル オブジェクトに埋められます。




実行環境が関数の場合、そのアクティベーション オブジェクト (AO) がスコープ チェーンの最初のオブジェクトとして使用され、2 番目のオブジェクトが包含環境、次のオブジェクトが包含環境の包含環境になります。 。 。 。 。 image


コードをコピー コードは次のとおりです。function a(x,y){
var b=x y;
return b;
}
var tatal=a(5,10);


このとき、ステートメント var total=a( 5,10); スコープチェーンは次のとおりです


関数の実行中、識別子の解決は、最初のオブジェクトから開始して、同じ名前の識別子が見つかるまで段階的に遡って検索するプロセスです。トラバースを続行し、見つからない場合はエラーを報告する必要はありません。 image

クロージャをもう一度見てみましょう

以前のブログでは、内部関数を呼び出す可能性がある限り、JavaScript は参照された関数を保持する必要があると結論付けていました。さらに、JavaScript ランタイムは、JavaScript ガベージ コレクターが対応するメモリ領域を解放する前に、最後の変数が破棄されるまで、この内部関数を参照するすべての変数を追跡する必要があります。振り返ってみると、親関数で定義された変数は子関数のスコープ チェーン内にあり、子関数が破棄されなければ、そのスコープ チェーン内のすべての変数と関数が維持され、破棄されません。 。

コードをコピー コードは次のとおりです。for(var i=0;i< elements.length ;i ){
elements[i].onclick=function(){
alert(i);
}
}


これは、前のブログで述べた典型的な間違いです。要素がアラートをクリックするたびに、このコードの要素にバインドされたクリック イベント ハンドラーのスコープ チェーンは次のようになります。

image

内部関数 (クリック イベント ハンドラーはいつでも呼び出すことができる) のため、そのスコープ チェーンは破棄できません (言うまでもなく、この例では i はグローバル スコープ内にあり、ページが更新されたときにのみ破棄できます) i の値 for ループが実行された後の長さの値は常に維持されるため、onclick がトリガーされるたびに長さが警告されます。

コードをコピー コードは次のとおりです。
for(var i=0;i< elements.length ;i ){
(function(n){
elements[n].onclick=function(){
alert(n);
}
})(i) ;
}

これはなぜ機能するのでしょうか? このとき、onclick によって参照される変数は n になり、関数が即時に実行されるため、各 onclick 関数はスコープ チェーン内で対応する n (0~length-1) を維持します。現時点ではそれです。

ついに

実際、実行環境とスコープ チェーンを理解すると、クロージャは明らかになりますが、上記の例からわかるように、クロージャはサブ関数にすべての変数、関数のスコープ チェーンを維持させます。メモリは大量のメモリを消費します。親関数で使用されなくなった変数は、使用するときに破棄してください。

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