ホームページ  >  記事  >  ウェブフロントエンド  >  JavaScriptの書き方と関数クロージャを詳しく解説

JavaScriptの書き方と関数クロージャを詳しく解説

高洛峰
高洛峰オリジナル
2017-01-20 13:12:421271ブラウズ

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. 関数にいくつかの属性を追加します

3.2. 変数を宣言し、変数に値として関数を割り当てます

3.3. この方法は一般的に使用されており、最も便利です。 var obj = {} は空のオブジェクトを宣言することです

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

4. クロージャの主な機能

クロージャはさまざまな場所で使用できます。その最大の用途は 2 つです。1 つは前述したように関数内の変数を読み取ること、もう 1 つはこれらの変数の値をメモリに保持することです。

4.1. ローカル変数を外部から読み取るにはどうすればよいですか?

さまざまな理由により、関数内でローカル変数を取得する必要がある場合があります。ただし、前述したように、これは通常の状況では不可能であり、回避策によってのみ実現できます。

それは、関数の中に別の関数を定義することです。

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

上記のコードでは、関数 f2 が関数 f1 の中に含まれています。このとき、f1 内のローカル変数はすべて f2 から見えます。ただし、その逆は機能しません。f2 内のローカル変数は f1 には見えません。これは、JavaScript 言語に特有の「チェーン スコープ」構造で、子オブジェクトはすべての親オブジェクトの変数をレベルごとに検索します。したがって、親オブジェクトのすべての変数は子オブジェクトから見えますが、その逆はありません。

f2 は f1 のローカル変数を読み取ることができるので、f2 が戻り値として使用される限り、f1 の外部にあるその内部変数を読み取ることはできません!

var Circle={
"PI":3.14159,
"area":function(r){
return this.PI * r * r;
}
};
alert( Circle.area(1.0) );//3.14159

4.2. 変数の値をメモリに保持するにはどうすればよいですか?

function f1(){
  var n=999;
  function f2(){
    alert(n); // 999
  }
}

このコードでは、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 を指します。 コードは次のとおりです:

function f1(){
  var n=999;
  function f2(){
    alert(n);
  }
  return f2;
}
var result=f1();
result(); // 999

this オブジェクトをクロージャがアクセスできる変数の外部スコープに保存します。クロージャ can パッケージはオブジェクトにアクセスします。コードは次のとおりです:

function f1(){
  var n=999;
  nAdd=function(){n+=1}
  function f2(){
    alert(n);
  }
  return f2;
}
var result=f1();
result(); // 999
nAdd();
result(); // 1000

6. クロージャとメモリ リーク

具体的には、HTML 要素がクロージャのスコープに格納されている場合、その要素は破棄できないことを意味します。以下のように:

var name = "The window";
var object = {
name:"My object",
getNameFun:function(){
return function(){
return this.name;
};
}
};
alert(object.getNameFun(){}); //"The window"(在非严格模式下)

上記のコードは要素イベント ハンドラーとしてクロージャを作成し、このクロージャは循環参照を作成します。無名関数は assignHandler() のアクティブオブジェクトへの参照を保存するため、要素への参照数を減らすことができません。無名関数が存在する限り、要素の参照番号は少なくとも 1 であるため、それによって占有されているメモリは再利用されません。

コードを書き換えることにより、内部のリサイクル不可能性の問題を解決します:

var name = "The window";
var object = {
name:"My object",
getNameFun:function(){
var that = this;
return function(){
return that.name;
};
}
};
alert(object.getNameFun(){}); //“My object”

上記のコードは要素を直接参照せずにクロージャを実装しており、参照は関数を含むアクティブなオブジェクトに保存されます。したがって、要素変数を null に設定して、要素変数が占有するメモリを正常にリサイクルできるようにする必要があります。

7. クロージャを使用する際の注意点

1) クロージャは関数内の変数をメモリに格納し、大量のメモリを消費するため、クロージャを悪用することはできません。そうしないと、Web 上でパフォーマンスの問題が発生します。 IE でメモリ リークが発生する可能性があります。解決策は、関数を終了する前に、未使用のローカル変数をすべて削除することです。

2) クロージャは、親関数内の変数の値を親関数の外に変更します。したがって、親関数をオブジェクトとして使用し、クロージャをそのパブリック メソッドとして使用し、内部変数をプライベート値として使用する場合は、親関数内の変数の値を自由に変更しないように注意する必要があります。

以上は編集者が紹介したJavaScriptのクロージャの書き方と機能について詳しく説明しました。ご質問があればメッセージを残していただければ編集者が返信させていただきます。時間。また、PHP 中国語 Web サイトをサポートしていただきありがとうございます。

JavaScript のクロージャの書き方と機能の詳細な説明については、PHP 中国語 Web サイトを参照してください。

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