閉鎖とは何ですか.

4762 ワード

閉パッケージ定義


閉包の具体的な定義には多くの説があり、これらの説は大きく2つに分けることができます。

  • 閉パケットは、その語法文脈において自由変数を引用する関数である.
  • の閉パケットは、関数とそれに関連する参照環境とを組み合うエンティティである.
  • :変数の役割ドメインは、ソースコードにおけるその位置によって決定する.
    多くの人はすべてかばんを閉じるのが1つの理解しにくい知識点だと思って、実はそうではありませんて、その定義がどんなに理解しにくいに関わらず、私达は自分でそれに対して1种の自分で理解することができる定義を形成すればいいだけで、そしてこのような自己理解の定義の正確性と実行可能性を保証します.
    ここでは、閉パッケージは、彼が関数であるかエンティティであるかにかかわらず、現在のコンテキストにアクセスできる環境変数であることを理解しています.このように見ると、関数内部の関数であろうと、単一定義の関数であろうと、関数がある箇所には閉パケットが存在する.

    閉パッケージの特性とメリット


    クローズドパッケージの機能:

  • の関数の内部は外部のパラメータと変数を参照することができる.
  • パラメータと変数はゴミ回収機構によって回収されない.

  • クローズドパッケージの使用のメリット

  • 変数をメモリに長期保存する
  • は、プライベートメンバー
  • を所有することができる
  • 関数内部に関数形式の閉パケットが存在する場合、グローバル変数の汚染
  • を回避することができる.

    例を挙げる


    関数の内部関数

    function init() {
      var name = "closure";
      function displayName() {
        alert(name);
      }
      displayName();
    }
    init();

    関数init()は、局所変数nameを作成し、displayName()という名前の関数を定義する.displayName() は内部関数であり、init()内に定義され、この関数内でのみ使用可能である.displayName()には独自のローカル変数はありませんが、外部関数の変数、すなわち親関数で宣言されたname変数にアクセスできます.

    閉パッケージでプライベートメソッドをシミュレートする

    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();
    alert(Counter1.value()); /*    0 */
    Counter1.increment();
    Counter1.increment();
    alert(Counter1.value()); /*    2 */
    Counter1.decrement();
    alert(Counter1.value()); /*    1 */
    alert(Counter2.value()); /*    0 */

    2つのカウンタがそれぞれの独立性を維持する方法に注意してください.makeCounter()関数が呼び出されるたびに、その環境は異なります.呼び出しのたびに、privateCounterには異なるインスタンスが含まれます.このような形式のクローズド・パッケージは、通常、オブジェクト向けUによって享受される多くの利点、特にデータの非表示およびパッケージングを提供する.

    ループ内の閉パッケージの作成:一般的なエラー

    Helpful notes will appear here

    E-mail:

    Name:

    Age:

    function showHelp(help) {
      document.getElementById('help').innerHTML = help;
    }
    
    function setupHelp() {
      var helpText = [
          {'id': 'email', 'help': 'Your e-mail address'},
          {'id': 'name', 'help': 'Your full name'},
          {'id': 'age', 'help': 'Your age (you must be over 16)'}
        ];
    
      for (var i = 0; i < helpText.length; i++) {
        var item = helpText[i];
        document.getElementById(item.id).onfocus = function() {
          showHelp(item.help);
        }
      }
    }
    
    setupHelp();

    このコードを実行すると、目的の効果が得られません.フォーカスがどの入力フィールドにあるかにかかわらず、年齢に関するメッセージが表示される.この問題の原因は、onfocusが閉パケットオブジェクトではなく閉パケット(setupHelp)に割り当てられた匿名関数であるためである.
    この問題を解決する1つの方法はonfocusを新しい閉パケットオブジェクトに指向させることである.
    function showHelp(help) {
      document.getElementById('help').innerHTML = help;
    }
    
    function makeHelpCallback(help) {
      return function() {
        showHelp(help);
      };
    }
    
    function setupHelp() {
      var helpText = [
          {'id': 'email', 'help': 'Your e-mail address'},
          {'id': 'name', 'help': 'Your full name'},
          {'id': 'age', 'help': 'Your age (you must be over 16)'}
        ];
    
      for (var i = 0; i < helpText.length; i++) {
        var item = helpText[i];
        document.getElementById(item.id).onfocus = makeHelpCallback(item.help);
      }
    }
    
    setupHelp();

    性能を考慮する.


    特定のタスクのためにパケットを閉じる必要がない場合は、処理速度やメモリ消費など、他の関数で関数を作成するのは賢明ではありません.パケットを閉じることはスクリプトのパフォーマンスに悪影響を及ぼすためです.
    たとえば、新しいオブジェクトまたはクラスを作成する場合、メソッドは通常、オブジェクトのコンストラクタではなく、オブジェクトのプロトタイプに関連付けられる必要があります.これは、コンストラクタが呼び出されるたびに、メソッドが再割り当てされるためです(つまり、各オブジェクトの作成).
    現実的ではないが、問題を説明する例を考えてみましょう.
    function MyObject(name, message) {
      this.name = name.toString();
      this.message = message.toString();
      this.getName = function() {
        return this.name;
      };
    
      this.getMessage = function() {
        return this.message;
      };
    }

    上記のコードは、閉パッケージのメリットを利用していません.したがって、次の一般的な形式に変更する必要があります.
    function MyObject(name, message) {
      this.name = name.toString();
      this.message = message.toString();
    }
    MyObject.prototype = {
      getName: function() {
        return this.name;
      },
      getMessage: function() {
        return this.message;
      }
    };