13

私は答えのコメントを読んでいて、このコメントを見ました:

[クロージャ] は foo の状態を永続化せず、(1) 返された関数と (2) 返されたときに参照されたすべての外部変数を含む特別なスコープを作成します。この特別なスコープはクロージャーと呼ばれます。

OK、ここまでは順調です。ここに私が知らなかった興味深い部分があります:

適切なケース... foo で定義された別の var がreturn 関数で参照されていない場合、それはクロージャスコープに存在しません。

それは理にかなっていると思いますが、これにはメモリの使用/パフォーマンス以外にどのような意味がありますか?

質問-- スコープ内のすべての変数がクロージャに含まれている場合、現在のモデルではできないことを何ができるようになりますか?

4

4 に答える 4

3

return 関数で参照されていない別の var が foo で定義されている場合、それはクロージャー スコープには存在しません。

これは完全に正確ではありません。変数は、関数自体の内部で (関数コードを見ることによって) 直接参照されていない場合でも、クロージャー スコープの一部です。違いは、エンジンが未使用の変数を最適化する方法です。

たとえば、クロージャー スコープ内の未使用の変数は、DOM 要素を操作しているときに (特定のエンジンで) メモリ リークを引き起こすことが知られています。たとえば、次の古典的な例を見てみましょう。

function addHandler() {
    var el = document.getElementById('el');
    el.onclick = function() {
        this.style.backgroundColor = 'red';
    }
}

ソース

上記のコードでは、(少なくとも IE と Mozilla の両方で) メモリ リークが発生しelます。これは、参照されていないにもかかわらず、クリック ハンドラ関数のクロージャ スコープの一部であるためです。これにより、ガベージ コレクションが参照カウントに基づいているため、削除できない循環参照が発生します。

一方、Chrome は別のガベージ コレクターを使用します。

V8 では、オブジェクト ヒープは 2 つの部分に分割されます。オブジェクトが作成される新しいスペースと、ガベージ コレクション サイクルを生き残ったオブジェクトがプロモートされる古いスペースです。オブジェクトがガベージ コレクション サイクルで移動されると、V8 はそのオブジェクトへのすべてのポインターを更新します。

これは、世代別または一時的なガベージ コレクタとも呼ばれます。より複雑ではありますが、このタイプのガベージ コレクターは、変数が使用されているかどうかをより正確に判断できます。

于 2013-04-04T02:43:52.863 に答える
1

JavaScript には固有のプライバシーの感覚がないため、関数スコープ (クロージャ) を使用してこの機能をシミュレートします。

あなたが参照している SO の回答は、 Addy Osmani がLearning JavaScript Design Patternsの重要性を説明する素晴らしい仕事をしているモジュールパターンの例です:

Module パターンは、クロージャーを使用して「プライバシー」、状態、および組織をカプセル化します。これは、パブリックおよびプライベートのメソッドと変数の組み合わせをラップする方法を提供し、断片がグローバル スコープに漏れたり、誤って別の開発者のインターフェイスと衝突したりするのを防ぎます。このパターンでは、パブリック API のみが返され、クロージャー内の他のすべてはプライベートに保たれます。

于 2013-04-04T02:36:35.127 に答える