エンクロージャ|コアJavaScript 5

17188 ワード

モジュールの意味と原理を理解する


特長

  • の多機能プログラミングにおける一般的な特性


  • outerの実行コンテキストが終了すると、内部関数を呼び出すことはできません.
    上のコードはinner関数の結果値のみouther 2に格納します.

    outerの実行コンテキストが終了しても、宣言された内部関数にアクセスできます.
    またouter変数も使用できます.

    内部関数の実行コンテキスト


    環境レコード:収集する情報がありません(宣言された変数はありません)
    外部環境参照:内部関数宣言位置のLexicalEnvironmentが参照にコピーされます->外部関数の辞書環境が保存されます.
    カーネル実行時(let outer2=outer())、outer関数は実行を停止しました->どのようにアクセスしますか?
    ==ゴミ収集器の挙動により
    変数が値を参照している場合、ゴミ収集器はその値を収集ターゲットに含めません.
    LexicalEnvironmentが関数の実行コンテキストの終了後もゴミ収集器の収集ターゲットから除外されている場合、参照領域変数の内部関数は唯一の外部伝達である.
    規格により、宣言時のLexicalEnvironmentは全てGCすることはないが、2019規格はChromeまたはNodeである.jsなどで使用されているv 8エンジンについては,内部関数で実際に使用されている変数のみを保持し,残りの最適化はGCとする.
    そのため、いわゆるシャーシです.
  • は、ある関数が宣言する変数を参照する内部関数にのみ発生する現象
  • である.
  • 外部関数のLexicalEnvironmentゴミ収集現象
  • ある関数Aを参照して宣言した変数Aの内部関数Bを外部に渡すと、Aの実行コンテキストが終了しても変数Aは消えない.

    エンクロージャとメモリ管理


    実行コンテキストが終了しても、モジュールには変数が存在します.
    ->ストレージ容量の継続的な使用
    需要が消えた後にメモリを消費しないように、識別子に非参照型の基本型データ(null/undefined)を割り当て、参照カウントを0にすることが望ましい.

    エンクロージャのメモリ解放例


    return

    let outer = (function() {
      let a = 1;
      let inner = function() {
        return ++a;
      }
      return inner;
    })();
    console.log(outer());
    console.log(outer());
    
    //outer 식별자의 inner함수 참조를 끊음.
    outer = null

    setInterval



    eventListener

    (function() {
      let count = 0;
      let button = document.createElement('button');
      button.innerText = 'click'
      
      let clickHandler = function() {
        console.log(++count, 'time clicked');
        if(count >= 10) {
          button.removeEventListener('click', clickHandler);
          // clickHandler 식별자의 함수 참조를 끊음
          clickHandler = null;
        }
      }
      button.addEventListener('click', clickHandler);
      document.body.appendChild(button)
    })

    エンクロージャ使用例


    コールバック関数で外部データを使用する場合


    1

    let fruits = ['banana', 'apple', 'lemon'];
    let $ul = document.createElement('ul');
    
    fruits.forEach(function(fruit){
      let $li = document.createElement('li');
      $li.innerText = fruit;
      $li.addEventListener('click', function() {
        alert('this is '+fruit)
      })
      $ul.appendChild($li)
    });
    document.body.appendChild($ul)

    2

    let fruits = ['banana', 'apple', 'lemon'];
    let $ul = document.createElement('ul');
    
    let alertFruit = function(fruit){
      alert('this is ' + fruit)
    }
    
    fruits.forEach(function(fruit){
      let $li = document.createElement('li');
      $li.innerText = fruit;
      $li.addEventListener('click', alertFruit.bind(null, fruit));
      $ul.appendChild($li)
    })
    document.body.appendChild($ul)
    addEventListenerはコールバック関数を呼び出すときに「イベントオブジェクト」を最初のパラメータに注入するためbindメソッドを使用してこの問題を解決します.
    しかし、この場合、次のような問題が発生します.
  • イベントオブジェクトがパラメータに移行する順序は
  • である.
  • 関数内部のthisは従来と異なる点:
  • 3

    let fruits = ['banana', 'apple', 'lemon'];
    let $ul = document.createElement('ul');
    
    let alertFruit = function(fruit){
      return function () {
        alert('this is ' + fruit)
      }
    }
    
    fruits.forEach(function(fruit){
      let $li = document.createElement('li');
      $li.innerText = fruit;
      $li.addEventListener('click', alertFruit(fruit));
      $ul.appendChild($li)
    })
    document.body.appendChild($ul)

    アクセス権制御(情報の非表示)


    モジュール内部の論理の外部曝露を最小限に抑え、モジュール間の結合を低減し柔軟性を向上させることを目的とする概念.
    outer関数から返される情報に外部からのみアクセスできます.return変数はpublicに変わります.そうしないとprivateになります.

    ローカル適用関数


    関数モジュールをコアテクノロジーとして使用すると、n個のパラメータを受け入れる関数にm個のパラメータを予め記憶してから、(n−m)個のパラメータを後でスキップして、元の関数の実行結果を得ることができます.

    部分関数を使用する最適な例-ジッタ


    同じイベントが短時間で大量に発生した場合、最初のイベントまたは最後のイベントのみが処理され、すべてのイベントは処理されません.
    スクロール、ローラー、mousemove、resizeなどのツールを使用してフロントエンドのパフォーマンスを最適化

    コリンかんすう


    複数のパラメータを受信する関数を1つのパラメータのみを受信する関数に分けてチェーン形式で順次呼び出す.
    必要な情報のみが受信され、必要な情報が受信されたときに転送される場合、関数の実行は、最後のパラメータの前=지연 실행に遅延される.

    ローカル適用関数との違い


    1回に1つのパラメータ
  • のみを渡す
  • の中間過程で関数を実行した結果、
  • を待って次のパラメータを得ることになった.
  • 最後のパラメータを渡す前にソース関数
  • を実行しない