JavaScript_基礎知識をもとにクロージャの基礎を共有

WBOY
リリース: 2016-05-16 17:29:11
オリジナル
944 人が閲覧しました

独立したオブジェクトとしてのスコープと関数の基本概念をよく理解していれば、クロージャの概念を理解し、実際のプログラミングの実践に適用するのは非常に簡単になります。

DOM イベント処理に関しては、ほとんどのプログラマは知らず知らずのうちにクロージャを使用しています。この場合、リークの問題はさておき、プログラマであっても、ブラウザに組み込まれた JavaScript エンジンのバグがメモリの問題を引き起こす可能性があります。自分自身をデバッグするときに混乱することがよくあります。
簡単なステートメントを使用して、JavaScript のクロージャの概念を説明します。JavaScript では、関数はオブジェクトであり、オブジェクトは属性のコレクションであり、属性の値はオブジェクトになる可能性があるため、次のように定義するのが自然になります。関数内の関数 if 関数 func 内で関数 inner を宣言し、関数の外側で inner を呼び出します。このプロセスはクロージャを生成します。
クロージャーの特徴:
まず例を見てみましょう。JavaScript の特徴を理解していなければ、理由を見つけるのは困難です:

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

var outter = [];
function clouseTest() {
var array = ["one", " two", "three", "four"];
for (var i = 0; i var x = {};
x.no = i;多くの初心者は次のような答えを思いつくかもしれません:

0
1
2
3

ただし、このプログラムを実行すると、結果は次のようになります:

4
4
4
4
実際、各反復でステートメント x.invoke = function(){print(i);} は実行されず、関数オブジェクトを構築するだけです。関数本体「print(i);」を追加するだけです。 i=4 の場合、反復は停止し、外部関数が戻ります。outer[0].invoke() が再度呼び出されるとき、i の値は依然として 4 であるため、外側の配列の各要素の呼び出しは i の値を返します。 :4。この問題を解決するにはどうすればよいでしょうか?匿名関数を宣言してすぐに実行できます:


コードをコピーします


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

var outter = [];
function clouseTest2() {
var array = ["one", "two", "three", "four"];
for (var i = 0; i var x = {};
x.text = array[i];
x .invoke = function(no){
;
outter.push(x);
}
}
clousetest2();
</script>


この例では、x.invoke に値を代入するときに、まず関数を返すことができる関数を実行し、それをすぐに実行します。このように、x.invoke の各イテレーターは、次のようなステートメントを実行することと同等です。これ:



コードをコピーします
コードは次のとおりです://x == 0 x.invoke = function(){print(0);}
//x == 1
x.invoke = function (){print(1);}
//x = = 2
x.invoke = function(){print(2);}
//x == 3
x.invoke = function(){print(3);}


こうすることで正しい結果が得られます。クロージャを使用すると、外部関数内に存在する変数を参照できます。ただし、作成時の変数の値は使用されず、代わりに外部関数内の変数の最後の値が使用されます。

クロージャの目的:

クロージャの概念が明確になったところで、クロージャの目的を見てみましょう。実際、クロージャを使用すると、さまざまなことができます。たとえば、オブジェクト指向のコーディング スタイルをシミュレートし、コードをよりエレガントかつ簡潔に表現し、いくつかの側面でコードの実行効率を向上させることができます。

キャッシュ:

別の例を見てみましょう。各呼び出しには非常に時間がかかるため、次のようにする必要があります。この関数を呼び出すと、まずキャッシュ内で値が検索され、見つからない場合は計算され、見つかった場合は値が返されます。見つかった値が直接返されます。 クロージャは外部参照を解放しないため、関数内の値を保持できるため、まさにこれを行うことができます。



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

var CachedSearchBox = (function () {
var queue = {},
count = [];
return {
attachSearchBox: function (dsid ) (キャッシュ内の DSID) {//結果がキャッシュにある場合

キャッシュ[dsid] = fsb;//キャッシュの更新
キャッシュの削除[count.shift() ];
; :





コードをコピー


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


var person = function( ){
//変数のスコープは関数内にあり、外部からはアクセスできません
var name = "default";

return {
getName : function(){
return name;
}, setName : function(newName){
name = newName;
}


結果は次のようになります:

未定義
デフォルト
ジャック

クロージャのもう 1 つの重要な用途は、オブジェクトをオブジェクト指向で実装することです。従来のオブジェクト言語は、異なるオブジェクト (クラスのインスタンス) が互いに干渉することなく独立したメンバーと状態を持つようにするためのクラス テンプレート メカニズムを提供します。 JavaScript にはクラスのようなメカニズムはありませんが、クロージャを使用することでそのようなメカニズムをシミュレートできます。上の例を見てみましょう:




コードをコピーします


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

function Person(){
var name = "default";

return {
getName : function(){
return name;
},
setName: function(newName){
name = newName;
}
}
};
var john = person();
print(john.getName()) ;
john.setName("john");
print(john.getName());

var jack = person();
print(jack.getName());
jack.setName("jack");
print(jack.getName());

実行結果は次のとおりです:
default
john
デフォルト
ジャック

JavaScript クロージャが注意すべき問題:
1. メモリ リーク:
インタープリタ自体の欠陥により、さまざまな JavaScript インタープリタ実装で、クロージャはメモリ リークを引き起こす可能性があります。メモリ リークは深刻な問題であり、ブラウザの応答速度に重大な影響を及ぼし、ユーザー エクスペリエンスを低下させ、さらにはブラウザが応答しなくなることもあります。 JavaScript インタプリタにはすべて、参照カウントの形式を採用するガベージ コレクション メカニズムがあり、オブジェクトの参照カウントがゼロの場合、このプロセスは自動的にリサイクルされます。ただし、クロージャの概念では、将来のある時点でローカル変数を使用する必要がある可能性があるため、このプロセスは複雑になります。循環参照が発生した場合、ガベージ コレクション メカニズムはこれらの外部参照を処理しません。 、オブジェクト A が B を参照し、B が C を参照し、C が A を参照すると、ガベージ コレクション メカニズムはその参照カウントがゼロではないと判断し、メモリ リークが発生します。

2. コンテキスト参照:

コードをコピーします コードは次のとおりです。 🎜>
$(function(){
var con = $("div#panel");
this.id = "content";
con.click(function() {
alert(this.id);//panel
});
});

ここでのalert(this.id)はどの値を指しますか?多くの開発者は、クロージャの概念に基づいて誤った判断を下す可能性があります:

content
その理由は、this.id にクリック コールバックに表示される値が割り当てられ、クロージャが参照することを形成するためです。 .id なので、戻り値は content です。ただし、実際には、このアラートは「パネル」をポップアップします。これは、クロージャがローカル変数を参照できるにもかかわらず、呼び出し元のオブジェクトの存在によって状況が少し微妙になるためです。クロージャーが呼び出されるとき (このパネルのクリック イベントが発生するとき)、ここでは jQuery オブジェクト con を参照します。匿名関数の this.id = "content" は、匿名関数自体に対して実行される操作です。 this が参照する 2 つは、同じオブジェクトを参照していません。

イベント ハンドラーでこの値にアクセスしたい場合は、いくつかの変更を加える必要があります:
コードをコピー コードは次のとおりです:
$(function(){
var con = $("div#panel");
this.id = "content" ;
var self = this;
con.click(function(){
alert(self.id);//content
});
});

このように、イベント処理関数に保存するのは this ではなく、外部ローカル変数 self への参照です。このテクニックには多くの実際的な応用例があり、次の章で詳しく説明します。他の命令型言語での「クロージャ」の説明や、実際のプロジェクトでのクロージャの適用など、クロージャについては第 9 章で詳しく説明します。

添付: 私のレベルが限られているため、記事に省略や誤りがあることは避けられません。また、文言自体が不適切である可能性もあります。タイムリーな修正や提案を歓迎します。この記事は他の人たちにインスピレーションを与えるためのものです、皆さんに感謝します!
関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート