以下は私の勉強メモです。JavaScript 初心者には非常に役立つはずです。
1. 変数のスコープ
クロージャを理解するには、まず Javascript の特殊な変数スコープを理解する必要があります。
変数のスコープは、グローバル変数とローカル変数の 2 種類にすぎません。
JavaScript 言語の特別な点は、グローバル変数を関数内で直接読み取ることができることです。
var n=999; function f1(){ alert(n); } f1(); // 999
一方、関数内のローカル変数は関数の外から読み取ることはできません。
function f1(){ var n=999; } alert(n); // error
ここで注意すべき点があります。関数内で変数を宣言する場合は、var コマンドを使用する必要があります。これを使用しない場合、実際にはグローバル変数を宣言していることになります。
function f1(){ n=999; } f1(); alert(n); // 999
2. ローカル変数を外部から読み取るにはどうすればよいですか?
さまざまな理由により、関数内でローカル変数を取得する必要がある場合があります。ただし、前述したように、これは通常の状況では不可能であり、回避策によってのみ実現できます。
それは、関数内に別の関数を定義することです。
function f1(){ var n=999; function f2(){ alert(n); // 999 } }
上記のコードでは、関数 f2 が関数 f1 の中に含まれています。この時点で、f1 内のすべてのローカル変数が f2 から見えます。ただし、その逆は機能しません。f2 内のローカル変数は f1 には見えません。これは、JavaScript 言語に特有の「チェーン スコープ」構造で、子オブジェクトはすべての親オブジェクトの変数をレベルごとに検索します。したがって、親オブジェクトのすべての変数は子オブジェクトから見えますが、その逆はありません。
f2 は f1 内のローカル変数を読み取ることができるので、f2 を戻り値として使用する限り、f1 の外部でその内部変数を読み取ることはできませんか?
function f1(){ var n=999; function f2(){ alert(n); } return f2; } var result=f1(); result(); // 999
3. クロージャの概念
前のセクションのコードの f2 関数はクロージャです。
さまざまな専門文献における「閉鎖」の定義は非常に抽象的で、理解するのが困難です。私の理解では、クロージャは他の関数の内部変数を読み取ることができる関数です。
JavaScript 言語では、関数内のサブ関数のみがローカル変数を読み込むことができるため、クロージャは単純に「関数内で定義された関数」として理解できます。
本質的に、クロージャは関数の内部と関数の外部を接続する橋です。
4. 閉鎖の目的
クロージャーはさまざまな場所で使用できます。その最大の用途は 2 つあり、1 つは前述したように関数内の変数を読み取ること、もう 1 つはこれらの変数の値をメモリに保持することです。
この文はどうやって理解できますか?以下のコードを見てください。
function f1(){ var n=999; nAdd=function(){n+=1} function f2(){ alert(n); } return f2; } var result=f1(); result(); // 999 nAdd(); result(); // 1000
このコードでは、result は実際にはクロージャ f2 関数です。これは 2 回実行され、1 回目の値は 999、2 回目の値は 1000 でした。これは、関数 f1 のローカル変数 n が常にメモリに格納され、f1 が呼び出された後に自動的にクリアされないことを証明しています。
なぜこのようなことが起こっているのでしょうか?その理由は、f1 が f2 の親関数であり、f2 がグローバル変数に割り当てられているため、f2 は常にメモリ内に存在し、f2 の存在は f1 に依存するため、f1 は常にメモリ内にあり、削除されないためです。呼び出しが完了すると、ガベージ コレクション メカニズム (ガベージ コレクション) によってリサイクルされます。
このコードでもう 1 つ注目すべき点は、「nAdd=function(){n =1}」という行です。まず、var キーワードが nAdd の前に使用されていないため、nAdd はローカル変数ではなくグローバル変数です。 。 変数。次に、nAdd の値は匿名関数であり、匿名関数自体もクロージャであるため、nAdd は関数の外部で関数内のローカル変数を操作できるセッターと同等です。
5. クロージャ使用時の注意点
1) クロージャによって関数内の変数がメモリに格納され、大量のメモリが消費されるため、クロージャを悪用することはできません。悪用しないと、Web ページでパフォーマンスの問題が発生し、Web ページでメモリ リークが発生する可能性があります。いえ。解決策は、関数を終了する前に、未使用のローカル変数をすべて削除することです。
2) クロージャは、親関数内の変数の値を親関数の外で変更します。したがって、親関数をオブジェクトとして使用し、クロージャをそのパブリック メソッドとして使用し、内部変数をプライベート値として使用する場合は、親関数内の変数の値を自由に変更しないように注意する必要があります。
6. 質問
次の 2 つのコードの結果を理解できれば、クロージャの動作メカニズムを理解できるはずです。
コード スニペット 1
var name = "The Window"; var object = { name : "My Object", getNameFunc : function(){ return function(){ return this.name; }; } }; alert(object.getNameFunc()());
コード スニペット 2
var name = "The Window"; var object = { name : "My Object", getNameFunc : function(){ var that = this; return function(){ return that.name; }; } }; alert(object.getNameFunc()());
以上がこの記事の全内容です。皆さんに気に入っていただければ幸いです。