クロージャ(Closure)のしくみとは?―JavaScript初心者のためのやさしい解説

こんにちは。ゆうせいです。

JavaScriptを学んでいると、こんなコードに出会うことがあります。

function outer() {
  let message = "こんにちは";

  function inner() {
    console.log(message);
  }

  return inner;
}

const greet = outer();
greet(); // → こんにちは

「えっ?outer()の中でしか宣言されてないmessageが、外に出た関数から使えてるの!?」「これってどういうこと?」

この「中の関数が、外の変数を記憶している」という不思議な現象こそが クロージャ(Closure) の正体です。

今回は、クロージャのしくみ・なぜ使われるのか・どんな場面で便利なのかを、丁寧に解説します。


クロージャとは?一言でいうと…

クロージャとは、「関数が、定義されたときのスコープ(変数の情報)を“記憶している”状態」のことです。

つまり、関数の外側で宣言された変数を“覚えている”関数のことなんです。


どうしてそんなことができるの?

JavaScriptでは、関数が定義されたときの「スコープ(変数の有効範囲)」を、関数が実行されるときまで保持するしくみがあります。

これを 「スコープチェーン」 といいます。

function outer() {
  let count = 0;

  return function () {
    count++;
    console.log(count);
  };
}

const counter = outer();
counter(); // 1
counter(); // 2

上記では countouter() の中で定義された変数ですが、counter()(inner関数)がずっとそれを覚えているため、毎回1ずつ増えていくのです!


図で理解:クロージャの構造

outer()
 ├── count(スコープ内に存在)
 └── inner()(この中からcountを参照)
         ↑
     関数がスコープを“記憶”している!

なぜクロージャが使われるの?

✅ 1. データのカプセル化(外部から直接変更できない)

function createCounter() {
  let count = 0;

  return {
    increment: function () {
      count++;
      return count;
    },
    get: function () {
      return count;
    }
  };
}

const counter = createCounter();
console.log(counter.increment()); // 1
console.log(counter.get());       // 1

count という変数は関数の外からは直接アクセスできないため、安全に管理できます。


✅ 2. 状態を“覚えておく”処理が書ける

function createGreeter(name) {
  return function () {
    console.log("こんにちは、" + name + "さん!");
  };
}

const greetTaro = createGreeter("太郎");
const greetHanako = createGreeter("花子");

greetTaro();   // → こんにちは、太郎さん!
greetHanako(); // → こんにちは、花子さん!

ここでは、name の値がそれぞれの関数に記憶されている=クロージャの仕組みです。


数式的に考えると…

通常の関数:

f(x) = x + 1

クロージャ的な関数:

f(y) = (x) => x + y

ここで y を外側のスコープから固定して、関数を返すという構造になっています。


よくある落とし穴:for文とクロージャ

for (var i = 0; i < 3; i++) {
  setTimeout(function () {
    console.log(i);
  }, 1000);
}
// → 3, 3, 3

「えっ!?なんで 0,1,2 じゃないの?」という例。

これは、varで宣言された変数 i1つしかないスコープに属していて、あとから参照されたときの値(3)だけが使われるため。

letを使うと個別にクロージャが作られて解決できます:

for (let i = 0; i < 3; i++) {
  setTimeout(function () {
    console.log(i);
  }, 1000);
}
// → 0, 1, 2


まとめ:クロージャの本質とは?

ポイント内容
何をする?関数が定義時のスコープを覚えている
なぜ使う?状態保持・情報の隠蔽・柔軟な関数生成
いつ作られる?関数が別の関数の内部で定義され、返されるとき
よくある用途カウンター、イベントハンドラ、カスタムAPI、非同期処理のラッピングなど

今後の学習のヒント

クロージャを使いこなすために、次のテーマも学んでおきましょう!

  • スコープとスコープチェーンの仕組み
  • 即時関数(IIFE)とクロージャの関係
  • 高階関数との組み合わせ
  • JavaScriptのモジュールパターン

クロージャは最初は「なんとなく」で構いません。

でも理解すればするほど、「この仕組みのおかげでJavaScriptはここまで柔軟なんだ」と感じられるはずです。

ぜひ、たくさん書いて、手と頭で覚えていきましょう!

セイ・コンサルティング・グループの新人エンジニア研修のメニューへのリンク

投稿者プロフィール

山崎講師
山崎講師代表取締役
セイ・コンサルティング・グループ株式会社代表取締役。
岐阜県出身。
2000年創業、2004年会社設立。
IT企業向け人材育成研修歴業界歴20年以上。
すべての無駄を省いた費用対効果の高い「筋肉質」な研修を提供します!
この記事に間違い等ありましたらぜひお知らせください。