C#のラムダ式にもclosuresがありますが、C#コミュニティや本ではほとんど議論されていません。 JavaScriptの人々や本が、C#の世界よりもclosuresについて語る方がはるかに多いと思います。何故ですか?
JavaScriptには名前空間のような機能がないため、あらゆる種類のグローバルオブジェクトを簡単に混乱させることができます。
そのため、独自の実行環境で一部のコードを分離できることが重要です。クロージャーはそれに最適です。
このクロージャーの使用は、コードを分離し、すべてをグローバルスコープに配置しない名前空間、クラスなどがあるC#のような言語では意味がありません。
JavaScriptコードの非常に一般的な方法は、次のように記述することです。
(function(){
// Some code
})();
ご覧のとおり、これは無名関数の宣言であり、すぐにその実行が続きます。したがって、関数内で定義されたすべてのものを外部からアクセスすることは不可能であり、グローバルスコープを台無しにすることはありません。この関数の実行コンテキストは、このコンテキスト内で定義されたネストされた関数のように、コールバックなどとして渡すことができるコードが使用する限り、存続します。
JavaScriptはC#とは非常に異なる言語です。オブジェクト指向ではなく、プロトタイプ指向です。これは、最後に非常に異なる実践につながります。
とにかく、クロージャーは良いので、C#でも使用できます。
編集:stackoverflowのチャットについていくつかの議論の後、私はこの回答を正確にする必要があると思います。
サンプルコードの関数はクロージャーではありません。ただし、この関数はローカル変数とネストされた関数を定義できます。これらのローカル変数を使用するすべてのネストされた関数はクロージャーです。
これは、グローバルスコープを台無しにせずに、一連の関数全体で一部のデータを共有する場合に役立ちます。これは、JavaScriptでの最も一般的なクロージャの使用法です。
クロージャは、このようないくつかのデータを共有するよりもはるかに強力ですが、現実的に考えてみましょう。ほとんどのプログラマは、関数型プログラミングについて何も知りません。 C#では、これらの種類の使用のためにクラスまたは名前空間を使用しますが、JSはこの機能を提供しません。
単にグローバルスコープを保護するだけでなく、クロージャを使用してもっと多くのことができますが、これはJSソースコードに表示されます。
JavaScriptのオブジェクト指向の一般的な実装はクロージャーに依存しているためと考えられます。簡単な例を見てみましょう:
function counter() {
var value = 0;
this.getValue = function() { return value; }
this.increase = function() { value++; }
}
var myCounter = new counter();
console.log(myCounter.getValue());
myCounter.increase();
console.log(myCounter.getValue());
メソッドgetValue
およびincrease
は実際にはクロージャーであり、変数value
をカプセル化します。
JavaScriptを「耐えられる」ものにするライブラリの多くがそれらを使用するためです。
JQuery 、 Prototype または MooTools を見てください。これらの各ライブラリは、反復の好ましい方法として、イテレータ関数を使用するコレクションのeach
メソッドを提供します。その関数は、外側のスコープの値にアクセスする場合、クロージャーになります。
[1,2,3].each(function(item) {
console.log(item);
});
そして、それだけではありません。Ajaxでのコールバック、Ext.jsでのイベント処理など、すべて関数を使用します。1回だけ呼び出される100数百もの関数でコードを膨らませたくない場合は、クロージャが適しています。
JavaScriptを使用した「適切な」コーディングはクロージャーに大きく依存するという他の回答にも同意します。ただし、それに加えて、機能が各言語でどれくらいの期間使用されているかが問題になっている可能性があります。 JavaScriptは、初期の実装以来、基本的にクロージャーを備えてきました。一方、C#は、Visual Studio 2008でリリースされた3.0以降でのみ使用されています。
私が遭遇した多くのC#プログラマーは、まだ2.0プロジェクトに取り組んでいます。また、3.0または4.0で動作している場合でも、2.0のイディオムを使用していることがよくあります。閉鎖が大好きです。うまくいけば、C#開発者の間で概念が広まるにつれて、それらはC#でより頻繁に使用されるようになるでしょう。
主な理由は、C#は静的に型指定されており、関数は単一の事前に定義された環境にしかアクセスできないため、クロージャーの有用性が妨げられるためです。
一方、JavaScriptでは、クロージャーにより、関数をオブジェクトプロパティとしてアクセスし、ファーストクラスのオブジェクトとしてメソッドとして動作させることができます。また、異なる環境に注入して、異なるコンテキストでサブルーチンを操作することもできます。