序章

この記事では、クロージャとは何か、JavaScriptがクロージャの恩恵を受ける理由の基本について説明します。

前提条件

この記事をフォローしたい場合は、次のものが必要になります。

  • JavaScript変数、関数、スコープ、およびコールバックに精通していること。

クロージャーの定義

クロージャは、変数によって保持される永続的なスコープとして定義できます。 JavaScriptやRubyなどの言語はクロージャをサポートしています。これにより、プログラミングブロックが実行された後でも、変数が親スコープへの参照を持つことができ、これらの変数がどこかに参照を持っている限り、クロージャが存在します。

次のクロージャの例を考えてみましょう。

function outerFunction() {
 let delayed = veryLongOperation();

 let innerFunction = function() { someCallback(delayed); }
}

innerFunctionは、delayedオブジェクトなどの親スコープ要素にアクセスできる関数です。

クロージャの使用

クロージャーとは何かを見てきましたが、なぜそれらが役立つのでしょうか。

JavaScriptは、実行に関しては非同期にすることができます。 操作が完了すると、コールバックを使用する必要があります。 このコールバックは、呼び出し元/親と同じ実行コンテキストで実行する必要があります。 つまり、親が使用できる変数または関数はすべて、コールバックでも使用できるようにする必要があります。 これらのコールバックにクロージャがない場合は、必要なスコープメンバーを手動でバインドする必要があります。

クロージャは、バックグラウンドでこれを処理することにより、私たちの生活をはるかに楽にします。 関数内に関数がある場合、内部関数はその存続期間を通じてスコープメンバーにアクセスできます。

次のクラス定義の例を考えてみましょう。

let classExample = function () {
  let randomNumber = Math.floor(Math.random() * 10);

  return function() {
    console.log(randomNumber);
  }
}

内部関数のスコープチェーンは、classExample関数のメンバーを含むように拡張されています。

クロージャが作用するもう1つの例は、カリー化中です。 カリー化は、アリティを減らすために複数の関数を返すプロセスです。 これは、関数型プログラミングのパラダイムで使用され、状態の変化を減らします。

クロージャをカリー化と一緒に使用して、JavaScriptクラスのプライベートメンバーを紹介できます。

function curryingExample() {
  let message = "Hello.";

  return {
    getMessage: function() { console.log('private message', message); }
  };
}

新しいcurryExample()インスタンスを作成します。

let curry = new curryingExample();

messageへのアクセスを試みます:

console.log('undefined message', curry.message);

console.log(curry.message);を実行すると、値はundefinedになります。

getMessage()を使用してみてください:

curry.getMessage();

curry.getMessage();を実行すると、値は"Hello."になります。

結論

クロージャはJavaScriptの非常に微妙でありながら強力な機能であり、クロージャを理解することは、真剣なJavaScript開発者になるための非常に重要なステップです。

これについては、KyleSimpsonのClosuresに関する優れた記事で詳しく説明されています。