🙄

若干わかった気になるJavaScriptのクロージャ

2025/02/08に公開

概要

クロージャってわかりづらいですよね
仕事中とかに出てきて?しか思い浮かばなかったかつ、よく、クロージャの説明に
「実行環境と関数を合体したものを1つに閉じ込めたものをクロージャと呼ぶ、関数自体のことをエンクロージャと呼ぶ」のような定義が書かれていますが、基本頭が回っていない私からするとこの説明では何もピンときませんでした・・・
なので、一旦簡潔な例でクロージャとは何なのかを何となく理解していこうというのが今回の目的です!

じゃあ結局何なんなのよクロージャって

一言で言うと、「関数と一緒に使いたい変数をまとめて管理しようねー」といった感じかなと思います!

説明する上で、数値をカウントアップさせる関数を使って、
関数と変数が一緒に使いたいパターンかつクロージャで解決できる状況を見ていきたいと思います!

  1. グローバルスコープだと変数がどこで変わるかわからない!
    →正常に、count変数の数値加算できるが、本来はcountはincrementのみで管理したい時、countはグローバル変数と定義しているので、どこからでも変更ができてしまう!
let count = 0; // 🔹 グローバル変数

function increment() {
  count++;  // 🔹 count を 1 増やす
  console.log(count);
}

function resetCount() {
  count = 100;  // 🚨 別の関数が `count` を変更!
}

increment(); // 出力: 1
increment(); // 出力: 2

resetCount();  // 🚨 `count` を勝手に 100 に変更!

increment(); // 出力: 101 (予期しない変更!)

  1. じゃあ、グローバルじゃなくてカウントをincrementする関数内で変数を持てばいいじゃない!
    →関数内で持つと外部参照はされないのでinclementだけがcount変数を管理できますが、毎回初期化されてしまう!
function increment() {
  let count = 0;  // 🔹 毎回 `count` を 0 に初期化
  count++;
  console.log(count);
}

increment(); // 出力: 1
increment(); // 出力: 1
increment(); // 出力: 1

上記のような事象を解決するのがクロージャです!

クロージャを用いた場合

実際にクロージャとやらを用いてみます!すると下記のようになります

function createCounter() {
  let count = 0; // 🔹 カウントを管理する変数
  return function () {
    count++; // 🔹 count を 1 増やす
    console.log(count); // 🔹 count を表示
  };
}

const counter = createCounter(); // 🔹 createCounter() を実行して関数を取得

counter(); // 出力: 1
counter(); // 出力: 2
counter(); // 出力: 3

上記のように実装することにより、先ほど問題だった

  1. 特定の関数のみで変数countを管理したい
  2. 正常にcount変数を更新する

がクリアできます。なぜこれでクリアできているかと言うと冒頭に記載した
「関数と一緒に使いたい変数をまとめて管理しようねー」が実行されているからです

・関数 = countを更新している無名関数
・一緒に使いたい変数 = count

にあたり、createCounterを実行することで、
counter変数は変数countを記憶する能力と、変数countを更新する能力が備わるといった具合になっています

まとめ

ざっくりですがクロージャについて説明しました!
実際にはこのような簡潔なコードではないため、
複雑で読み解くのが難しい場合もあるかもしれませんが
概要を知っておくだけで見え方が違うのかなと思うので、
クロージャという言葉・実際に該当するものが出てきた時にひるまなくなれればいいなと思います!

Discussion