javascript(一)は包装を閉じます.
7401 ワード
クローズド(closure)は関数式プログラミングの概念で、20世紀の60年代に現れて、最初にクローズドを実現した言語はSchemeで、それはLISPの方言です.その後のクローズド特性は他の言語で広く吸収された.クローズドの厳密な定義は「関数(環境)とその閉じられた自由変数からなる集合体」です.この定義は皆さんには分かりにくいので、まず例と厳密な説明を通して、クローズドとは何かを説明してから、いくつかのクローズドの古典的な用途を例に挙げて説明します.
閉包とは何ですか
分かりやすく言うと、JavaScriptの関数は一つのクローズドですが、通常の意味ではネストされた関数はもっとクローズドな特性を表しています.以下の例を見てください.
クローズドの用途ネストされたコールバック関数は、ネストを実現するためのコールバック関数と、隠しオブジェクトの詳細という二つの主要な用途がある.まず、下記のコード例を見て、ネストのコールバック関数を理解しましょう.下記のコードはNode.jsでMongoDBを使って簡単にユーザーを増やす機能です.
2プライベートメンバーを実現するには、JavaScriptのオブジェクトにはプライベート属性がないということは、オブジェクトの属性ごとに外部に露出されていることを知っています.このようにすれば、例えば対象のユーザが直接に属性を修正し、対象の内部データの整合性が破壊されるなどの危険性があります.JavaScriptは、すべての私有属性の前に下線を付けることを約束しています.この属性は私有であることを示しています.外部オブジェクトは直接読んで書いてはいけません.しかし、これは非公式の約束です.対象の利用者がそうしないと仮定すると、もっと厳しい仕組みがありますか?答えはあります.クローズドで実現できます.前の例を見てみましょう.
JavaScriptオブジェクトのプライベートメンバーを実現するための詳細については、参照してください.http://javascript.crockford.com/private.html.
閉包とは何ですか
分かりやすく言うと、JavaScriptの関数は一つのクローズドですが、通常の意味ではネストされた関数はもっとクローズドな特性を表しています.以下の例を見てください.
var generateClosure = function() {
var count = 0;
var get = function() {
count ++;
return count;
};
return get;
};
var counter = generateClosure();
console.log(counter()); // 1
console.log(counter()); // 2
console.log(counter()); // 3
このコードには、GEnerate Closeure()関数にローカル変数countがあり、初期値は0です.getという関数がもう一つあります.getはその親の役割領域、つまりgenerate Cloosure()関数のcount変数を1増加し、countの値を返します.generate Closeure()の戻り値はget関数です.外部では、counter変数を通じて、generate Cloosure()関数を呼び出し、その戻り値、つまりget関数を取得しました.次に何回かのcounterを呼び出します.帰るたびに値が1ずつ増えていることを発見しました.上記の例の特徴を見てみましょう.通常の命令式プログラミングの考え方では、countはゲナートCloosure関数内部の変数です.そのライフサイクルはゲナートCloureが呼び出される時期です.ゲナートCloureがコールスタックから戻ると、count変量申請の空間も解放されます.問題は、GEnerate Cloosure()の呼び出しが終了した後、counter()は「リリースされた」count変数を引用していますが、エラーがないばかりか、counter()を呼び出すたびに修正してcountに戻りました.これはどういうことですか?これはまさにクローズドという特性です.関数が内部で定義された関数を返すと、閉じたパケットが返される関数だけでなく、この関数の定義環境も含めて生成されます.上記の例では、外部変数counterによって関数generate Cloosure()の内部関数getが引用されると、counterとgenerante Cloure()の局所変数は一つのクローズドである.もしまだはっきりしていないなら、次のこの例はあなたの理解を助けることができます.var generateClosure = function() {
var count = 0;
var get = function() {
count ++;
return count;
};
return get;
};
var counter1 = generateClosure();
var counter2 = generateClosure();
console.log(counter1()); // 1
console.log(counter2()); // 1
console.log(counter1()); // 2
console.log(counter1()); // 3
console.log(counter2()); // 2
上記の例は、クローズドパケットがどのように生成されるかを説明している.counter 1およびcounter 2は、それぞれの動作環境に属する2つのクローズド・パケットの例を生成する.generate Cloosure()がget関数に戻るときに、getが引用する可能性のあるgenerate Cloosure()関数の内部変数(つまりcount変数)をひそかに返し、メモリにコピーを生成した後、generate Cloure()が返す関数の2つのインスタンスcounter 1とcounter 2は独立していると理解できる.クローズドの用途
exports.add_user = function(user_info, callback) {
var uid = parseInt(user_info['uid']);
mongodb.open(function(err, db) {
if (err) {callback(err); return;}
db.collection('users', function(err, collection) {
if (err) {callback(err); return;}
collection.ensureIndex("uid", function(err) {
if (err) {callback(err); return;}
collection.ensureIndex("username", function(err) {
if (err) {callback(err); return;}
collection.findOne({uid: uid}, function(err) {
if (err) {callback(err); return;}
if (doc) {
callback('occupied');
} else {
var user = {
uid: uid,
user: user_info,
};
collection.insert(user, function(err) {
callback(err);
});
}
});
});
});
});
});
};
Node.jsやMongoDBに慣れていないなら、大丈夫です.詳細を理解する必要はありません.大体のロジックを見ればいいです.このコードには、閉じられたパケットの階層的な入れ子が使用されています.各階層の入れ子は一つのコールバック関数です.コールバック関数はすぐには実行されません.対応する要求が処理された後、要求された関数によってコールバックされるのを待っています.ネストの各層にはcalbackの参照があり、最奥層には外層定義のuid変数も用いられていることがわかる.クローズド機構の存在により、外層関数が実行されても、そのスコープ内で申請された変数は解放されない.なぜなら、内側の階層の関数はこれらの変数にも参照される可能性があるので、完全に入れ子の非同期ループが実現される.2プライベートメンバーを実現するには、JavaScriptのオブジェクトにはプライベート属性がないということは、オブジェクトの属性ごとに外部に露出されていることを知っています.このようにすれば、例えば対象のユーザが直接に属性を修正し、対象の内部データの整合性が破壊されるなどの危険性があります.JavaScriptは、すべての私有属性の前に下線を付けることを約束しています.この属性は私有であることを示しています.外部オブジェクトは直接読んで書いてはいけません.しかし、これは非公式の約束です.対象の利用者がそうしないと仮定すると、もっと厳しい仕組みがありますか?答えはあります.クローズドで実現できます.前の例を見てみましょう.
var generateClosure = function() {
var count = 0;
var get = function() {
count ++;
return count;
};
return get;
};
var counter = generateClosure();
console.log(counter()); // 1
console.log(counter()); // 2
console.log(counter()); // 3
counter()を呼び出してこそ、クローズド内のcount変数にアクセスでき、ルールに従って1を追加することができます.これ以外にcount変数を見つけることはできません.この簡単な例の啓発を受けて、私達は1つの対象を閉じて包装することができて、1つの“訪問器”の対象だけを返して、細い点に対して隠れることを実現することができます.JavaScriptオブジェクトのプライベートメンバーを実現するための詳細については、参照してください.http://javascript.crockford.com/private.html.