こんにちは、まだJavaScriptでクロージャーを使用する正確な使用法についてはわかりません。クロージャーについては「クロージャーは、外側の(囲んでいる)関数の変数—スコープチェーンにアクセスできる内部関数です」という考えがありますが、私は知りませんjavascript でクロージャーを使用する理由を理解してください。
5 に答える
代わりに想像してみてください
alert("Two plus one equals" + (2+1) );
使用するすべての定数に対して変数を宣言する必要があります。
var Two = 2;
var One = 1;
var myString = "Two plus one equals";
alert(myAlert + (Two + One) );
定数を使用する前に、すべての定数に対して変数を定義する必要があるとしたら、気が狂ってしまうでしょう。
クロージャーの場合のローカル変数へのアクセスは利点ですが、主な役割 (有用性) は、関数を主な式、定数として使用することです。
取った
function Div1OnClick()
{
Counter.clickCount ++;
}
$('#Div1').click(Div1OnClick);
対
$('#Div1').click(function(){ Counter.clickCount++; });
一度使用するためだけに「上の」名前空間に新しい関数名を作成することはありません。実際のアクティビティは、それが使用されている場所にあります。コードが書かれた場所まで追跡する必要はありません。最初に定義して名前を付けてから名前で呼び出す代わりに、実際の関数を定数として使用できます。クロージャーに関連する警告、利点、およびトリックは無数にありますが、それはそれらを販売する 1 つのプロパティです。
一般に、クロージャーの主な用途は、コンテキストから状態を取得する関数を作成することです。関数にはキャプチャされた変数がありますが、それらはパラメーターとして渡されないことを考慮してください。
したがって、関数のファミリーを作成する方法と考えることができます。たとえば、1 つの値だけが異なる一連の関数が必要であるが、その値をパラメーターとして渡すことができない場合は、クロージャーを使用してそれらを作成できます。
Mozilla Developer Network には、クロージャに関する優れた紹介があります。次の例を示します。
function init() {
var name = "Mozilla";
function displayName() {
alert(name);
}
displayName();
}
init();
この場合、関数displayName
は変数をキャプチャしましたname
。現状では、この例はあまり役に立ちませんが、関数を返す場合を考えることができます:
function makeFunc() {
var name = "Mozilla";
function displayName() {
alert(name);
}
return displayName;
}
var myFunc = makeFunc();
myFunc();
ここで、関数は変数をキャプチャしたmakeFunc
関数を返します。これで、その関数を変数に代入することで外部から呼び出すことができます。displayName
name
myFunc
この例を続けるには、キャプチャされた変数name
が実際にパラメーターであるかどうかを考えてみましょう。
function makeFunc(name) {
function displayName() {
alert(name);
}
return displayName;
}
var myFunc = makeFunc("Mozilla");
myFunc();
makeFunc
ここでは、パラメーターとして渡されたテキストを使用してメッセージを表示する関数を作成することがわかります。そのため、その変数の値のみで変化する関数のファミリ全体を作成できます ("Mozilla"
例では)。この関数を使用すると、メッセージを複数回表示できます。
ここで重要なのは、メッセージに表示される値がカプセル化されていることです。クラスのプライベートフィールドが他の言語で値を隠すのと同様の方法で、この値を保護しています。
これにより、たとえば、カウントアップする関数を作成できます。
function makeFunc(value) {
function displayName() {
alert(value);
value++;
}
return displayName;
}
var myFunc = makeFunc(0);
myFunc();
この場合、myFunc に格納されている関数を呼び出すたびに、最初の 0、次の 1、2 などの次の番号が取得されます。
より高度な例は、同じく Mozilla Developer Network の「Counter」「class」です。モジュール パターンを示します。
var Counter = (function() {
var privateCounter = 0;
function changeBy(val) {
privateCounter += val;
}
return {
increment: function() {
changeBy(1);
},
decrement: function() {
changeBy(-1);
},
value: function() {
return privateCounter;
}
}
})();
alert(Counter.value()); /* Alerts 0 */
Counter.increment();
Counter.increment();
alert(Counter.value()); /* Alerts 2 */
Counter.decrement();
alert(Counter.value()); /* Alerts 1 */
ここでは、変数を進めるメソッドと減らすCounter
メソッドを持つオブジェクトであることがわかります。メソッドを呼び出して、この変数の値を照会することができます。increment
privateCounter
decrement
value
privateCounter
これがアーカイブされる方法は、変数が宣言されている隠しスコープを作成する無名関数の自動呼び出しです。これで、この変数は、その値を取得する関数からのみアクセスできるようになります。
クロージャーは、JavaScript で多くの追加機能を実装するために使用される強力な構成要素です。たとえば、クロージャーを使用して、次のようにプライベート状態を公開できます。
function getCounter() {
var count = 0;
return function () {
return ++count;
};
}
var counter = getCounter();
alert(counter()); // 1
alert(counter()); // 2
alert(counter()); // 3
上記の例では、呼び出し時にgetCounter
プライベート変数を作成しますcount
。次に、インクリメントして返す関数を返しcount
ます。したがって、返される関数は、変数を閉じて、スコープ外にcount
なった後でも変数にアクセスできるという意味でクロージャーです。count
これは、数行に詰め込まれた多くの情報です。分解してみましょうか?
さて、変数には人間と同じように寿命があります。彼らは生まれ、生き、そして死ぬ。スコープの開始は変数の誕生を示し、スコープの終了は変数の終了を示します。
JavaScript には関数スコープしかありません。したがって、関数内で変数を宣言すると、関数の先頭 (変数が生まれた場所) に引き上げられます。
宣言されていない変数にアクセスしようとすると、ReferenceError
. ただし、後で宣言された変数にアクセスしようとすると、undefined
. これは、JavaScript の宣言が巻き上げられているためです。
function undeclared_variable() {
alert(x);
}
undeclared_variable();
宣言されていない変数にアクセスしようとすると、ReferenceError
.
function undefined_variable() {
alert(x);
var x = "Hello World!";
}
undefined_variable();
関数の後半で宣言されている変数にアクセスしようとするとundefined
、宣言のみが巻き上げられるため、取得されます。定義は後ほど。
スコープに戻ると、変数はスコープ外になると死にます(通常、変数が宣言されている関数が終了するとき)。
たとえば、次のプログラムはグローバル スコープで宣言されていないReferenceError
ので、を返します。x
function helloworld() {
var x = "Hello World!";
}
helloworld();
alert(x);
クロージャーは、変数が宣言されている関数が終了したときでも変数にアクセスできるため、興味深いものです。例えば:
function getCounter() {
var count = 0;
return function () {
return ++count;
};
}
var counter = getCounter();
alert(counter()); // 1
alert(counter()); // 2
alert(counter()); // 3
上記のプログラムでは、変数count
は関数で定義されていますgetCounter
。したがって、ends を呼び出すとgetCounter
、変数count
も死ぬはずです。
しかし、そうではありません。これは、getCounter
にアクセスする関数を返すためcount
です。したがって、その関数 ( ) が生きている限りcounter
、変数count
も生き続けます。
この場合、() が返される関数は、 ofと呼ばれる変数を閉じるcounter
ため、クロージャと呼ばれます。count
upvalue
counter
用途
説明で十分です。とにかく閉鎖が必要なのはなぜですか?
getCounter
前に述べたように、クロージャーの主な用途は、関数の場合と同様にプライベートな状態を公開することです。
クロージャーのもう 1 つの一般的な使用例は、部分適用です。例えば:
function applyRight(func) {
var args = Array.prototype.slice.call(arguments, 1);
return function () {
var rest = Array.prototype.slice.call(arguments);
return func.apply(this, rest.concat(args));
};
}
function subtract(a, b) {
return a - b;
}
var decrement = applyRight(subtract, 1);
alert(decrement(1)); // 0
上記のプログラムには、 という関数がありましたsubtract
。部分適用を使用してdecrement
、このsubtract
関数から呼び出される別の関数を作成しました。
ご覧のとおり、このdecrement
関数は実際には変数andを閉じるクロージャです。func
args
クロージャーについて知っておく必要があるのは、これでほとんどすべてです。
これにより、何度も繰り返したり、コールバック関数に多数のパラメーターや引数を指定したりすることなく、ロジックを簡潔に表現できます。
ここで利用可能な詳細情報があります: javascript クロージャーの利点?
情報隠蔽のためです。
var myModule = (function (){
var privateClass = function (){};
privateClass.prototype = {
help: function (){}
};
var publicClass = function (){
this._helper = new privateClass();
};
publicClass.prototype = {
doSomething: function (){
this._helper.help();
}
};
return {
publicClass: publicClass
};
})();
var instance = new myModule.publicClass();
instance.doSomething();
JavaScript では、ppp (public、protected、private) プロパティを持つクラスがないため、クロージャを使用して情報を非表示にする必要があります。クラスレベルでは非常に高価になるため、コード品質を向上させるためにできる唯一のことは、モジュールレベルでクロージャーを使用し、そのクロージャーでプライベートヘルパークラスを使用することです。したがって、閉鎖は情報を隠すためのものです。安価ではなく、リソース (メモリ、CPU など) がかかるため、適切な場所でクロージャーを使用する必要があります。したがって、情報隠蔽のためにクラスレベルで使用しないでください。コストがかかりすぎるためです。
コールバックを使用してメソッドをインスタンスにバインドする別の使用法。
Function.prototype.bind = function (context){
var callback = this;
return function (){
return callback.apply(context, arguments);
};
};
バインドされた関数の典型的な使用法は、非同期呼び出しによるものです: defer、ajax、イベントリスナーなど...
var myClass = function (){
this.x = 10;
};
myClass.prototype.displayX = function (){
alert(this.x);
};
var instance = new myClass();
setTimeout(instance.displayX.bind(instance), 1000); //alerts "x" after 1 sec