JavaScriptのクローズドを解読します.

6026 ワード

一番簡単なカウンターから、需要に応じてコードを最適化していきます.
Cloosures are not magic
Funebug
可読性を保証するために、本文は直訳ではなく意訳を採用する.また、この著作権は元の作者に帰属し、翻訳は学習にのみ使用されます.
JavaScript初心者にとって、クローズドはとても不思議なものです.このブログは非常にシンプルなコード例によってクローズドを説明します.
カウンター
私達の目標はカウンタを実現することです.その効果は以下の通りです.
increment();  // Number of events: 1
increment();  // Number of events: 2
increment();  // Number of events: 3
increment()を実行するたびに、「Number of events:N」が出力され、Nは毎回1を加算することが分かります.
このカウンターの一番直観的な実現方法は以下の通りです.
var counter = 0;

function increment() 
{
  counter = counter + 1;
  console.log("Number of events: " + counter);
}
複数のカウンタ
以上のコードはとても簡単です.しかし、第二のカウンターが必要な時、問題が発生します.もちろん、私達は2つの重複カウンターを実現できます.
var counter1 = 0;

function incrementCounter1() 
{
  counter1 = counter1 + 1;
  console.log("Number of events: " + counter1);
}

var counter2 = 0;

function incrementCounter2() 
{
  counter2 = counter2 + 1;
  console.log("Number of events: " + counter2);
}

incrementCounter1();  // Number of events: 1
incrementCounter2();  // Number of events: 1
incrementCounter1();  // Number of events: 2
明らかに、上記のコードは非常に冗長で、最適化が必要です.もっと多くのカウンターが必要な場合、この方法はあまり現実的ではないです.この時には、不思議なカバンが必要です.
クローズドでカウンタを実現
複数のカウンターが必要です.冗長コードを除去したいなら、クローズドを使用できます.
function createCounter() 
{
  var counter = 0;

  function increment() 
  {
    counter = counter + 1;
    console.log("Number of events: " + counter);
  }

  return increment;
}

var counter1 = createCounter();
var counter2 = createCounter();

counter1(); // Number of events: 1
counter1(); // Number of events: 2
counter2(); // Number of events: 1
counter1(); // Number of events: 3
コードでは、2つの独立したカウンタcounter 1とcounter 2を作成し、それぞれカウントし、互いに不撓不屈にしました.コードは見ていておかしいです.分解して分析してもいいです.
まず、createCounterを見に来ました.
  • は、局所変数counter
  • を作成しました.
  • は、counter変数に1を加えることができる局所関数incrementを作成しました.
  • は、局所関数increment()を返します.なお、関数呼び出しの結果ではなく関数自体が返されます.
  • 見たところ、createCounter関数は私達が最初に定義したカウンタと非常に似ています.唯一の違いは、createCounterがカウンタを一つの関数にカプセル化することです.したがって、私たちはそれをクローズドと呼びます.
    分かりにくいのは、createCounter関数を使ってカウンタを作成すると、実際に新しい関数が作成されるということです.
    // fancyNewCounter         
    var fancyNewCounter = createCounter();
    クローズドの不思議なところは.createCounter関数を使ってカウンタincrementを作成するたびに、対応するカウンタ変数を作成します.また、戻ってきたincrement関数は常にcounter変数を記憶します.
    もっと重要なのは、このカウンタ変数は相互に独立していることです.たとえば、2つのカウンタを作成すると、各カウンタは新しいカウンタ変数を作成します.
    //         1    
    var counter1 = createCounter();
    counter1(); // Number of events: 1
    counter1(); // Number of events: 2
    
    //  1         2    
    var counter2 = createCounter();
    counter2(); // Number of events: 1
    
    //  2         1    
    counter1(); // Number of events: 3
    カウンタ名
    複数のカウンタの出力情報はすべて「Number of events:N」と混同されやすい.各カウンタに名前を付けることができれば、より便利です.
    var catCounter = createCounter("cats");
    var dogCounter = createCounter("dogs");
    
    catCounter(); // Number of cats: 1
    catCounter(); // Number of cats: 2
    dogCounter(); // Number of dogs: 1
    createCounterに新しいcounter Nameパラメータを伝えることによって、この点を簡単に行うことができます.
    function createCounter(counterName) 
    {
      var counter = 0;
    
      function increment() 
      {
        counter = counter + 1;
        console.log("Number of " + counterName + ": " + counter);
      }
    
      return increment;
    }
    このように、createCounter関数が返したカウンタは、同時に二つの局所変数を記憶します.counter Nameとcounter.
    カウンタコール方式を最適化する
    前の実施形態によれば、私たちはcreateCounter関数を呼び出してカウンタを返すことができます.戻りのカウンタを直接呼び出して1を足すことができます.これは直感的ではありません.次のように呼んでくれればいいです.
    var dogCounter = createCounter("dogs");
    dogCounter.increment(); // Number of dogs: 1
    実現コード:
    function createCounter(counterName) 
    {
      var counter = 0;
    
      function increment() 
      {
        counter = counter + 1;
        console.log("Number of " + counterName + ": " + counter);
      };
    
      return { increment : increment };
    }
    以上のコードはオブジェクトに戻ります.このオブジェクトにはincrementメソッドが含まれています.
    decrementを追加する方法
    今はカウンタにdecrementを追加できます.
    function createCounter(counterName) 
    {
      var counter = 0;
    
      function increment() 
      {
        counter = counter + 1;
        console.log("Number of " + counterName + ": " + counter);
      };
    
      function decrement() 
      {
        counter = counter - 1;
        console.log("Number of " + counterName + ": " + counter);
      };
    
      return {
        increment : increment,
        decrement : decrement
      };
    }
    
    var dogsCounter = createCounter("dogs");
    
    dogsCounter.increment(); // Number of dogs: 1
    dogsCounter.increment(); // Number of dogs: 2
    dogsCounter.decrement(); // Number of dogs: 1
    プライベートメソッドを追加
    前のコードには2行のコードが重複しています.つまりconsolie.log文です.したがって、counterの値を印刷するためのdisplay()方法を作成することができます.
    function createCounter(counterName) 
    {
      var counter = 0;
    
      function display() 
      {
        console.log("Number of " + counterName + ": " + counter);
      }
    
      function increment() 
      {
        counter = counter + 1;
        display();
      };
    
      function decrement() 
      {
        counter = counter - 1;
        display();
      };
    
      return {
        increment : increment,
        decrement : decrement
      };
    }
    
    var dogsCounter = createCounter("dogs");
    
    dogsCounter.increment(); // Number of dogs: 1
    dogsCounter.increment(); // Number of dogs: 2
    dogsCounter.decrement(); // Number of dogs: 1
    display関数はincrement()関数とdecrement()関数と似ていますが、実はかなり違います.私たちはdisplay()関数を返したオブジェクトに追加していません.これは以下のコードが間違っていることを意味します.
    var dogsCounter = createCounter("dogs");
    dogsCounter.display(); // ERROR !!!
    この時、display()は一つのプライベートな方法に相当します.私達はcreateCounter()関数の中でしか使えません.
    クローズドとオブジェクト指向プログラミング
    オブジェクト指向プログラミング(OOP)に接触したことがあるなら、ここで関連するコンテンツはOOPのクラス、オブジェクト、オブジェクト属性、共有方法とプライベート方法などの概念と非常に似ていることが分かります.
    パケットを閉じて、OOPと似ています.データとデータを操作する方法を結びつけます.したがって、OOPが必要なときは、クローズドパケットを使用して実現することができる.
    締め括りをつける
    クローズドはJavaScriptの素晴らしい特性です.それを把握して、私達はいくつかのよくあるプログラミングの需要に余裕を持って対応できます.
    著作権声明:転載する時、作者のFunebugと本文の住所を明記してください.https://blog.fundebug.com/201...