ホームページ > 記事 > ウェブフロントエンド > JavaScriptの書き方と関数クロージャを詳しく解説
1. クロージャとは何ですか? クロージャは、別の関数のスコープ内の変数にアクセスできる関数です。
簡単に言うと、JavaScript では内部関数の使用が許可されています。つまり、関数定義と関数式は別の関数の関数本体に配置されます。さらに、これらの内部関数は、すべてのローカル変数、パラメータ、およびそれらが存在する外部関数で宣言された他の内部関数にアクセスできます。クロージャは、これらの内部関数の 1 つが、それらを含む外部関数の外側で呼び出されるときに形成されます。
2. 変数のスコープ
クロージャを理解するには、まず変数のスコープを理解する必要があります。
変数のスコープはグローバル変数とローカル変数の2種類に過ぎません。
JavaScript 言語の特別な点は、グローバル変数を関数内で直接読み取ることができることです。
内部関数のスコープチェーンには外部関数のスコープが含まれているため、内部関数は外部関数の変数にアクセスできます。
次のように理解することもできます。内部関数のスコープは外部関数のスコープに広がります。 function;
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
3. クロージャを記述して使用するいくつかの方法
3.1. 関数に属性を追加します
function Circle(r) { this.r = r; } Circle.PI = 3.14159; Circle.prototype.area = function() { return Circle.PI * this.r * this.r; } var c = new Circle(1.0); alert(c.area()); //3.14159
3.2. このメソッドを使用して変数に値を代入します
var Circle = function() { var obj = new Object(); obj.PI = 3.14159; obj.area = function( r ) { return this.PI * r * r; } return obj; } var c = new Circle(); alert( c.area( 1.0 ) ); //3.14159
、最も便利です。 var obj = {} は空のオブジェクトを宣言することです
var Circle={ "PI":3.14159, "area":function(r){ return this.PI * r * r; } }; alert( Circle.area(1.0) );//3.14159
4. クロージャーの主な機能
クロージャーはさまざまな場所で使用できます。その最大の用途は 2 つです。1 つは前述したように関数内の変数を読み取ること、もう 1 つはこれらの変数の値をメモリに保持することです。
4.1. ローカル変数を外部から読み取るにはどうすればよいですか?
さまざまな理由により、関数内でローカル変数を取得する必要がある場合があります。ただし、前述したように、これは通常の状況では不可能であり、回避策によってのみ実現できます。
それは、関数の中に別の関数を定義することです。
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
4.2. 変数の値をメモリに保持するにはどうすればよいですか?
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. クロージャとこのオブジェクト
このオブジェクトをクロージャで使用すると、いくつかの問題が発生する可能性があります。匿名関数の実行はグローバルであるため、その this オブジェクトは通常 window を指します。 コードは次のとおりです:
var name = "The window"; var object = { name:"My object", getNameFun:function(){ return function(){ return this.name; }; } }; alert(object.getNameFun(){}); //"The window"(在非严格模式下)
this オブジェクトをクロージャがアクセスできる変数の外部スコープに保存します。アクセスするとオブジェクトが消えてしまいます。コードは次のとおりです:
var name = "The window"; var object = { name:"My object", getNameFun:function(){ var that = this; return function(){ return that.name; }; } }; alert(object.getNameFun(){}); //“My object”
6. クロージャとメモリ リーク
具体的には、HTML 要素がクロージャのスコープに格納されている場合、その要素は破棄できないことを意味します。以下のように:
function assignHandler(){ var element = document.getElementById("someElement"); element.onclick = function(){ alert(element.id); } }
上記のコードは要素イベント ハンドラーとしてクロージャを作成し、このクロージャは循環参照を作成します。無名関数は assignHandler() のアクティブオブジェクトへの参照を保存するため、要素への参照数を減らすことができません。無名関数が存在する限り、要素の参照番号は少なくとも 1 であるため、それによって占有されているメモリは再利用されません。
コードを書き直すことで、内部のリサイクル不可能性の問題を解決します。
function assignHandler(){ var element = document.getElementById("someElement"); var id = element.id; element.onclick = function(){ alert(id); } element = null; }
上記のコードは、クロージャが要素を直接参照しないことと、参照が関数を含むアクティブなオブジェクトに保存されることを認識しています。したがって、要素変数を null に設定して、要素変数が占有するメモリを正常にリサイクルできるようにする必要があります。
7. クロージャーの使用に関する注意事項
1) クロージャは関数内の変数をメモリに格納し、大量のメモリを消費するため、クロージャを悪用することはできません。悪用しないと、Web ページでパフォーマンスの問題が発生し、IE でメモリ リークが発生する可能性があります。解決策は、関数を終了する前に、未使用のローカル変数をすべて削除することです。
2) クロージャは、親関数内の変数の値を親関数の外に変更します。したがって、親関数をオブジェクトとして使用し、クロージャをそのパブリック メソッドとして使用し、内部変数をプライベート値として使用する場合は、親関数内の変数の値を自由に変更しないように注意する必要があります。
以上は編集者が紹介したJavaScriptのクロージャの書き方と機能について詳しく説明しました。ご質問があればメッセージを残していただければ編集者が返信させていただきます。時間。また、PHP 中国語 Web サイトをサポートしていただきありがとうございます。
JavaScript のクロージャの書き方と機能の詳細な説明については、PHP 中国語 Web サイトを参照してください。