カテゴリ: JavaScript 更新日: 2026/07/07

JavaScriptクロージャーとコールバック関数の関係を初心者向けに完全解説

JavaScriptのクロージャーとコールバック関数の関係
JavaScriptのクロージャーとコールバック関数の関係

先生と生徒の会話形式で理解しよう

生徒

「先生、JavaScriptでよく聞くクロージャーって何ですか?」

先生

「クロージャーとは、関数とその関数が作られたときの環境(変数など)を一緒に覚えておける仕組みです。簡単に言うと、関数が自分の周りの変数をずっと覚えている状態ですね。」

生徒

「なるほど。でもコールバック関数とどう関係があるんですか?」

先生

「コールバック関数は、別の関数に渡して後で実行される関数です。クロージャーの仕組みがあるから、コールバック関数は自分が作られたときの変数も覚えて実行できます。」

生徒

「それって、変数を忘れずに使えるってことですか?」

先生

「そうです!だから非同期処理やイベント処理でもクロージャーが大活躍します。」

1. クロージャーとは?

1. クロージャーとは?
1. クロージャーとは?

クロージャーとは、関数の中で定義された変数の情報を関数が覚えている状態のことです。これにより、関数の外からはアクセスできない変数を安全に保持できます。JavaScriptでは、関数が作られるときにそのスコープ(変数環境)も一緒に保存されます。


function createCounter() {
  let count = 0;
  return function() {
    count++;
    return count;
  }
}

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

この例では、counter関数がcount変数を覚えているので、呼び出すたびに値が増えていきます。

2. コールバック関数とは?

2. コールバック関数とは?
2. コールバック関数とは?

コールバック関数とは、別の関数に渡して後で呼び出される関数です。例えば、ボタンをクリックしたときに動作する関数や、非同期処理の結果を受け取る関数がコールバック関数です。


function greet(name, callback) {
  callback("こんにちは、" + name + "さん");
}

greet("太郎", function(message) {
  console.log(message);
});
// こんにちは、太郎さん

ここで渡した無名関数がコールバック関数です。

3. クロージャーとコールバック関数の関係

3. クロージャーとコールバック関数の関係
3. クロージャーとコールバック関数の関係

コールバック関数は、呼ばれるタイミングが関数定義の後になることがあります。そのとき、クロージャーのおかげで作られたときの変数を覚えて使えます。


function makeMultiplier(x) {
  return function(y) {
    return x * y;
  }
}

const double = makeMultiplier(2);
console.log(double(5)); // 10

このdouble関数は、作られたときのx=2を覚えています。これがクロージャーの力です。

4. 非同期処理でのクロージャー活用例

4. 非同期処理でのクロージャー活用例
4. 非同期処理でのクロージャー活用例

非同期処理では、コールバック関数が後から実行されますが、クロージャーを使うことで当時の変数を保持できます。


for (let i = 1; i <= 3; i++) {
  setTimeout(function() {
    console.log(i);
  }, i * 1000);
}
// 1秒後: 1, 2秒後: 2, 3秒後: 3

letを使うことで、クロージャーが各ループのiを覚えてくれます。varだと全て最後の値を表示してしまう点に注意です。

5. イベント処理でのクロージャー活用

5. イベント処理でのクロージャー活用
5. イベント処理でのクロージャー活用

ボタンなどのイベント処理でもクロージャーは便利です。イベントハンドラは後で呼ばれるため、作られたときの変数を覚えておけます。


function setupButton(buttonId, msg) {
  document.getElementById(buttonId).addEventListener("click", function() {
    alert(msg);
  });
}

setupButton("btn1", "ボタン1がクリックされました");
setupButton("btn2", "ボタン2がクリックされました");

この場合、各ボタンごとに異なるメッセージを覚えたクロージャーが作られています。

6. クロージャーを使ったデータ隠蔽

6. クロージャーを使ったデータ隠蔽
6. クロージャーを使ったデータ隠蔽

クロージャーは変数を外部から直接変更できないように隠すこともできます。これにより安全に値を管理できます。


function createSecret() {
  let secret = "これは秘密です";
  return {
    getSecret: function() { return secret; },
    setSecret: function(newSecret) { secret = newSecret; }
  };
}

const mySecret = createSecret();
console.log(mySecret.getSecret()); // これは秘密です
mySecret.setSecret("新しい秘密");
console.log(mySecret.getSecret()); // 新しい秘密

直接secretにアクセスできず、クロージャーを通してのみ操作できます。

7. クロージャーを理解するコツ

7. クロージャーを理解するコツ
7. クロージャーを理解するコツ

クロージャーは「関数が作られたときの環境を覚えている」とイメージするとわかりやすいです。コールバック関数や非同期処理、イベントハンドラなどと一緒に使われる場面で特に力を発揮します。


function outer() {
  let value = "覚えています";
  return function inner() {
    console.log(value);
  };
}

const fn = outer();
fn(); // 覚えています

この例でも、inner関数が外側のvalueを覚えていることが確認できます。

8. まとめに代わる理解のポイント

8. まとめに代わる理解のポイント
8. まとめに代わる理解のポイント

クロージャーとコールバック関数を一緒に考えると、JavaScriptで非同期処理やイベント処理を行う際に重要な基礎知識となります。変数のスコープや記憶の仕組みを理解することで、安全で効率的なコードを書けるようになります。

まとめ

まとめ
まとめ

今回の記事では、JavaScriptにおけるクロージャーとコールバック関数の関係を徹底的に解説しました。クロージャーは関数が作られたときの環境を保持する仕組みであり、変数や状態を安全に管理することができます。コールバック関数は別の関数に渡され、後で実行される関数ですが、このコールバック関数が作られた時点の変数環境をクロージャーが覚えているため、非同期処理やイベント処理において非常に便利です。これにより、関数が呼ばれるタイミングに関わらず必要な変数や状態を正確に利用できることがわかりました。

特に重要なポイントは、変数のスコープの違いと、letvarの使い分けです。ループ内での非同期処理では、letを使うことで各イテレーションの変数をクロージャーとして保持できます。また、クロージャーを活用したデータ隠蔽の方法も紹介しました。これにより、外部から直接変更できない安全な状態管理が可能となり、セキュアで予測可能なコードを書くことができます。

実際に手を動かして確認することが、クロージャーやコールバック関数の理解を深める近道です。以下に簡単なサンプルを再掲します。


function createCounter() {
  let count = 0;
  return function() {
    count++;
    return count;
  }
}

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

この例では、counter関数が作られたときのcountを覚え続けており、呼び出すたびに増加することが確認できます。クロージャーによる変数の記憶と、コールバック関数を使った処理のタイミング制御が密接に関連していることが理解できます。

また、イベント処理でもクロージャーが有効です。ボタンごとに異なるメッセージを覚えたクロージャーを作ることで、ユーザー操作に応じた柔軟な挙動を実現できます。


function setupButton(buttonId, msg) {
  document.getElementById(buttonId).addEventListener("click", function() {
    alert(msg);
  });
}

setupButton("btn1", "ボタン1がクリックされました");
setupButton("btn2", "ボタン2がクリックされました");

このように、JavaScriptでの非同期処理、イベント処理、状態管理においてクロージャーとコールバック関数は切っても切れない関係にあります。理解しておくことで、複雑な処理や非同期処理のバグを未然に防ぎ、保守性の高いコードを書くことが可能です。

先生と生徒の振り返り会話

生徒

「先生、クロージャーとコールバック関数の関係が少しずつわかってきました。要するに、コールバック関数が後で実行されても、クロージャーのおかげで必要な変数を覚えてくれているんですね。」

先生

「その通りです。クロージャーは関数が作られた時点のスコープを保持するので、コールバック関数や非同期処理の中でも安心して変数を使えます。」

生徒

「じゃあ、イベントハンドラでボタンごとに違うメッセージを表示するのも、クロージャーが働いているからできるんですね。」

先生

「その通りです。クロージャーを理解すると、非同期処理やイベント処理での変数管理が圧倒的に楽になります。そして、データを外部から直接変更されないようにする隠蔽も簡単にできます。」

生徒

「なるほど。クロージャーを使うことで安全に変数を管理できるし、コールバック関数で非同期処理もスムーズに扱えるんですね。」

先生

「その通りです。今日学んだクロージャーとコールバック関数の関係は、JavaScriptを本格的に使う上での基礎中の基礎です。繰り返し練習して、手を動かして確認することが理解を深める鍵です。」

カテゴリの一覧へ
新着記事
New1
JavaScript
JavaScriptのスコープとは?ローカル変数・グローバル変数の違いと使い分け
New2
TypeScript
TypeScriptで型の合成時に発生する型エラーの対処法を徹底解説!初心者にもわかりやすく解説
New3
TypeScript
TypeScriptでAPI呼び出しをラップするユーティリティ関数の設計完全ガイド!初心者向けにAxiosやFetchの使い方を解説
New4
TypeScript
TypeScriptのMapped Typesとインターフェースの連携方法を徹底解説!初心者でも理解できる型変換の基本
人気記事
No.1
Java&Spring記事人気No1
JavaScript
JavaScriptのループで無限ループが起きる原因と対策を初心者向けに徹底解説!
No.2
Java&Spring記事人気No2
JavaScript
JavaScriptのインストール方法まとめ!Windows・Mac・Linux別にステップ解説
No.3
Java&Spring記事人気No3
JavaScript
JavaScriptの文字列の長さを取得する(lengthプロパティ)
No.4
Java&Spring記事人気No4
TypeScript
TypeScriptのファイル分割とimport/exportの基本を徹底解説!初心者でも安心のやさしい入門
No.5
Java&Spring記事人気No5
TypeScript
TypeScriptでコメントを書く正しい書き方と使い分け【初心者向けにやさしく解説】
No.6
Java&Spring記事人気No6
JavaScript
JavaScriptでクエリパラメータを取得する方法を完全解説 URLSearchParamsの使い方を初心者向けに丁寧に説明
No.7
Java&Spring記事人気No7
TypeScript
TypeScriptでパスエイリアスを設定する方法!baseUrlとpathsでコードをスッキリ整理
No.8
Java&Spring記事人気No8
JavaScript
JavaScriptのプリミティブ型と参照型の違いを初心者向けに解説