閉鎖とは何ですか?
クロージャとは? クロージャとは、静的言語にはない新しい機能です。しかし、クロージャは複雑すぎて理解できないものではありません。つまり、クロージャは関数のローカル変数のコレクションですが、これらのローカル変数は関数が戻った後も存在し続けます。クロージャとは、関数が戻った後に関数の「スタック」が解放されないことを意味します。また、これらの関数スタックがスタック上に割り当てられるのではなく、関数内で別の関数が定義されると、クロージャが発生することも理解できます。 。 バッグ。
クロージャ = 関数内で作成された関数 (略して内部関数) + 関数作成時の環境情報
したがって、クロージャは匿名関数と同じではありません。ただし、一部の人は関数内で作成された関数を クロージャ関数 と呼びますが、私は実際には正確ではないと思います。
次のコードを見てみましょう:
function init() { var name = "Zilongshanren"; // name 是在 init 函数里面创建的变量 // displayName() 是一个内部函数,即一个闭包。注意,它不是匿名的。 function displayName() { console.log(name); } //当 displayName 函数返回后,这个函数还能访问 init 函数里面定义的变量。 return displayName; } var closure = init(); closure(); Zilongshanren undefined
displayName は、init 関数内で作成された関数です。ここでは name 変数など、init 関数の内部スコープのすべての情報が含まれています。 displayName 関数が返されると、関数自体が作成時の環境情報、つまり init 関数の name 変数を保持します。
クロージャとは何をするのですか?
クロージャとは何かを理解した後、「これは理解するのがとても難しいのですが、何に使うのですか?」と尋ねるかもしれません。
JS にはプライベート メソッドを作成する方法がないため、Java や C++ とは異なり、プライベート プロパティやメソッドを定義するための private キーワードがありません。 JS では、関数だけが独自のスコープに属するオブジェクトを作成できます。JS にはブロック スコープがありません。これについては後ほど詳しく紹介する記事を書きたいと思います。
プログラミングのベテランなら誰でも、プログラムを上手に書くにはカプセル化と抽象化をうまく使う必要があることを知っています。プライベート プロパティとメソッドを定義できないということは、カプセル化と抽象化がまったく使用できないことを意味します。 。 。
プライベートなものを定義することはできません。すべての変数と関数はパブリックです。明らかに問題があります。グローバルは悪です。
クロージャは私たちの救世主です!
次のコードを見てみましょう:
var makeCounter = function() { var privateCounter = 0; function changeBy(val) { privateCounter += val; } return { increment: function() { changeBy(1); }, decrement: function() { changeBy(-1); }, value: function() { return privateCounter; } } }; var counter1 = makeCounter(); var counter2 = makeCounter(); console.log(counter1.value()); /* Alerts 0 */ counter1.increment(); counter1.increment(); console.log(counter1.value()); /* Alerts 2 */ counter1.decrement(); console.log(counter1.value()); /* Alerts 1 */ console.log(counter2.value()); /* Alerts 0 */ 0 2 1 0 undefined
ここでのprivateCounter変数とchangeByは両方ともプライベートであり、makeCounter関数の外部には完全に見えません。このようにして、makeCounter を通じて生成したオブジェクトは、そのプライベート データとプライベート メソッドをすべて非表示にします。
これを見て何か思い出しますか?
ははは、これはただのOOではないですか?データとデータを操作するためのメソッドをカプセル化し、パブリック インターフェイス呼び出しを通じてデータ処理を完了します。
もちろん、プロトタイプ継承を使用して OO を実装することもできると言うかもしれません。はい、私たちも含めて、ほとんどの人が今そうしています。ただし、コードの一部を理解するには、そのすべての継承チェーンを理解する必要があるため、継承を理解するのは常に非常に困難です。コードにバグがあると、デバッグが非常に困難になります。
まだまだ先の話ですが、クロージャを正しく使用する方法を見てみましょう。
クロージャーを正しく使用するには?
クロージャはメモリを占有し、JS エンジンの実行効率にも影響を与えるため、コードが頻繁に実行される場合は、このコードでクロージャを使用することを慎重に検討する必要があります。
オブジェクトを作成する関数を見てみましょう:
function MyObject(name, message) { this.name = name.toString(); this.message = message.toString(); this.getName = function() { return this.name; }; this.getMessage = function() { return this.message; };} var myobj = new MyObject(); var myobj = new MyObject();
新しいオブジェクトを生成するために呼び出されるたびに、2 つのクロージャが生成されます。プログラム内にそのような MyObject オブジェクトが何千もある場合、より多くのメモリを消費することになります。
正しいアプローチは、プロトタイプ チェーンを使用することです:
function MyObject(name, message) { this.name = name.toString(); this.message = message.toString(); } MyObject.prototype.getName = function() { return this.name; }; MyObject.prototype.getMessage = function() { return this.message; }; var myobj = new MyObject();
これで、MyObject プロトタイプには 2 つのメソッドが定義されています。new を通じてオブジェクトを作成すると、これら 2 つのメソッドはプロトタイプ上に 1 つのコピーのみを持つことになります。
クロージャのパフォーマンスはどうですか?
クロージャも関数ですが、追加の環境情報を格納するため、理論的には純粋な関数よりも多くのメモリを消費し、クロージャを解釈して実行するときに JS エンジンがより多くのメモリを消費します。ただし、両者のパフォーマンスの差は 3% ~ 5% です (これは Google から取得したデータであり、あまり正確ではない可能性があります)。
しかし、閉鎖のメリットは間違いなく大きいです。クロージャとステートレス プログラミングをもっと使用して、バグを遠ざけましょう。
クロージャを理解すると、FP パラダイムの Js クラス ライブラリのほとんどとその背後に隠された設計アイデアを理解できます。もちろん、クロージャだけでは不十分です。FP、ステートレス、ラムダ計算などの概念によって洗脳されることも必要です。
この記事を読み終えた後、皆さんが js クロージャーを理解できるようになることを願っています。
関連する推奨事項:
以上がJavaScriptのクロージャとは何ですかの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。