🗝️

JavaScriptのクロージャーについて確認する

2023/11/14に公開

1.記事の目的

JavaScriptのクロージャーという概念について、気になったので調べてみました。

https://developer.mozilla.org/ja/docs/Web/JavaScript/Closures

クロージャは、組み合わされた(囲まれた)関数と、その周囲の状態(レキシカル環境)への参照の組み合わせです。言い換えれば、クロージャは内側の関数から外側の関数スコープへのアクセスを提供します。JavaScript では、関数が作成されるたびにクロージャが作成されます。

例えば、関数の外側から関数内で定義している変数を使用することはできません。

function Hello() {
  const value = "Hello!";
  console.log(value);
}
Hello(); // console.logに"Hello!"と表示してくれる
console.log(value); // undefined

これは関数ごとにスコープというものができていて、そのスコープ内を外部から参照することができないからです。

https://developer.mozilla.org/ja/docs/Glossary/Scope

しかし一方で、JSの関数は自分を囲むスコープにある変数を参照することができます。
それがクロージャーという機能です。

2.クロージャーとは

下記のようなコードでよく説明されます。

function displayName() {
  const name = "JavaScript"; // nameは、displayNameが作成するローカル変数
  function callName() {
    console.log(name); // 親関数で宣言された変数を使用できる
  }
  callName();
}
displayName(); // console.logに"JavaScript"と表示される

nameという変数はdisplayNameという関数で定義していますが、それをdisplayNameの内部で定義されている変数で使用することができます。

MDNにも書いてありますし、下記の記事で詳細に解説されていますが、JSの関数は全てクロージャーです。

https://qiita.com/takeharu/items/4975031faf6f7baf077a

JavaScriptの関数は、常に内側の関数から外側の関数スコープへのアクセスを提供してくれるということですね。

3.プライベートメソッドを作ることができる

クロージャーで面白いと感じたことは、メソッドを作成することができるという点です。

const counter = (function () {
  let privateCounter = 0;
  function changeBy(val) {
    privateCounter += val;
    console.log(privateCounter);
  }

  return {
    increment() {
      changeBy(1);
    },

    decrement() {
      changeBy(-1);
    },
  };
})(); // 関数を呼び出す

counter.increment(); // 1

counter.increment(); // 2

counter.decrement(); // 1

関数を呼び出した戻り値にはオブジェクトがセットされています。
関数を呼び出し+戻り値のオブジェクト呼び出しを組み合わせることで、内部関数を操作することができます。

4.まとめ

JSの関数は全てクロージャーの機能を持っているというのがポイントですね。

技術的な誤りがあれば、コメントいただけると嬉しいです。

Discussion