まずはWikipediaから定義を見てみましょう
コンピュータサイエンスにおいて、クロージャ(英語: Closure)は、字句クロージャ(Lexical Closure)または関数クロージャ(Function Closure)とも呼ばれ、自由変数の関数を指します。参照された自由変数は、関数が作成された環境を離れた後も関数とともに残ります。したがって、クロージャは関数とそれに関連する参照環境で構成されるエンティティである、という別の言い方もできます。クロージャは実行時に複数のインスタンスを持つことができ、異なる参照環境と同じ関数の組み合わせによって異なるインスタンスが生成されることがあります。
この文を簡単に理解するには、次の 2 つの重要なポイントがあります:
1. 自由変数 2. 関数 (自由変数の参照)。
変数を定義するとき、それに制約を指定しない場合、それは自由変数です。 例:
x ∈ (0,99) f(x,y)
関数 f(x,y) では、x は制約変数、y は自由変数です。
具体的に JavaScript での例を見てください:
var x = 0; function foo (y) { var z = 2; return x + y + z;}foo (3); // 3
数学的思考に変換すると、関数 foo は実際にはこの foo(x,y) のようになるはずですが、関数のパラメーターは実際には制約されていることがわかります。関数 によると、つまり、実際の自由変数は x だけです。
これにより、簡単な定義が得られます。 関数内に、ローカル変数でも仮パラメータでもない変数がある場合、それはクロージャを形成すると考えることができます。
ほとんどすべての言語で、同じ名前の変数は最も近い場所で検索されます。見つからない場合は、親スコープに移動します。これをスコープチェーンと呼びます。
クロージャー関数では、通常、自由変数は親によって提供されます。次の例を見てください:
function foo(x) { var tmp = 3; function bar(y) { console.log(x + y + (++tmp)); } bar(10);}foo(2)
上記の定義によれば、bar は自由変数を持ち、クロージャーですが、foo はそうではありません。
それでは、どうすれば foo をクロージャにできるでしょうか?
var x = 0;function foo() { var tmp = 3; function bar(y) { console.log(x + y + (++tmp)); } bar(10);}// 其实转换一下,形如function foo2() { var tmp = 3; //function bar(y) { console.log(x + 10 + (++tmp)); //} // bar(10);}
この時点で、foo はクロージャと見なすことができます。
この時点で、これは私たちが通常見る JS クロージャとは異なると思う人もいるかもしれません。私たちが通常見るクロージャは次のようなものです: 例はこのブログからのものです
function foo(x) { var tmp = new Number(3); return function (y) { alert(x + y + (++tmp)); }}var bar = foo(2); // bar 现在是一个闭包bar(10);
この関数は実際に書き換えることができるようです。次のようになります。
bar = function (y) { // foo(2) alert(2 + y + (++tmp))}
明らかに、 tmp は元の定義に準拠する自由変数であり、 bar は自由変数を持つ関数です。
では、tmp はどこに存在するのでしょうか?
foo(2)を実行すると、tmp=3の変数が生成されます。この変数は return 関数によって参照されるため、再利用されません。 return 関数の自由変数は、スコープ チェーンに従って値を検索します。 bar関数はfoo(2)で定義されているので、まずfoo(2)の変数領域から変数tmpを探して演算します。
注: スコープチェーンの問題については、次の記事で分析します。
そういえば、モジュールモードを入れてください。
var Module = (function () { var aaa = 0; var foo = function () { console.log(aaa); } return { Foo: foo }})();// 或者(function () { var aaa = 0; var foo = function () { console.log(aaa); } window.Module = { Foo: foo }})();
上記の 2 つの例は、モジュール自体が単なるオブジェクトですが、return 関数自体がクロージャを形成し、スコープがクリーンで他の関数を汚染しないことに注意してください。
これについて言うと、これが別のカテゴリであると考える友人もいるはずです?ローカル変数とアクセス可能な関数を持ちます。はい、見た目の点では、クロージャとクラスは非常によく似ていると思います。
Java を例に挙げます。
class Foo { private int a; int Say( int b ) { return a + b; } }
上記の Foo では、関数 Say の a は関数スコープの外にあり、自由変数です。 Say は関数クロージャーを形成すると考えることができます。ただし、js との違いは、インスタンス メソッドはクラス、つまりオブジェクトのインスタンスを通じて呼び出す必要があることです。
Java の設計では、アクセス許可、プライベート、プロテクト、デフォルト、パッケージが明確に定義されており、これは呼び出しの標準化における先駆的な取り組みです。また、変数や関数にはアクセス許可を定義するためのキーワードがあり、各クラスに属しており、明確であるため、Java プログラマはクロージャの実装をほとんど考慮しません。
クラス実装の観点からクロージャを理解していれば、クロージャの使用が推奨されない理由を簡単に理解できます。
クロージャが呼び出されるたびに、クロージャ関数に必要ないくつかの自由変数を保存するためのスコープが生成されます。これにより、メモリの無駄が発生しやすくなります。 Java プログラミングでも、気軽に新しいオブジェクトを作成することはお勧めできません。
前回の記事でbind、call、applyという点について触れましたが、 オブジェクト指向なのでこれをbindする必要があります。
オブジェクト指向についてですが、オブジェクト指向の利点は、理解しやすく、保守しやすく、再利用しやすいことだと思います。これは、複数人で大規模なプロジェクトを開発する場合のパフォーマンス要件をはるかに上回ります。
ムーアの法則が失速した現在でも、メモリは以前に比べて非常に安価であるため、パフォーマンス要件は古くから極端であり、現在ではコードの可読性が一般的に主張されています。
このカラフルなコードの世界を創造したスーパーエキスパートがいて、より多くの人にプログラミングの楽しさを体験してもらうために、より理解しやすいプログラミング言語を設計し、さまざまなコンパイラーやパーサーを発明しました...
もし。 1+1 のプログラムを書くだけで、オブジェクト指向である必要はありません。人間が機械に対してスーパーロジックとメモリを備えられるのであれば、オブジェクト指向は必要ありません。
以上がJSのクロージャとクラスを理解する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。