JavaScriptのコールバック関数とは?基本から実践まで徹底解説

JavaScriptのコールバック関数と非同期処理の関係を表現したイメージ
JavaScriptにおけるコールバック関数の役割と非同期処理の流れをイメージしたアイキャッチ画像

JavaScriptを学ぶうえで避けて通れない概念のひとつが「コールバック関数」です。非同期処理やイベント処理など、実務でも頻繁に登場するため、正しく理解することが重要です。

本記事では、コールバック関数の基本から具体的な使い方、注意点までを体系的に解説します。

コールバック関数とは?

コールバック関数とは、関数の引数として渡され、あとで実行される関数のことです。

通常の関数はその場で実行されますが、コールバック関数は「特定のタイミングで呼び出される」という特徴があります。

基本構造

function mainFunction(callback) {
  console.log("メイン処理開始");
  callback(); // 渡された関数を実行
}

function subFunction() {
  console.log("コールバック関数が実行された");
}

mainFunction(subFunction);

実行結果

メイン処理開始
コールバック関数が実行された

このように、関数を引数として渡すことで、処理のタイミングを柔軟に制御できます。

なぜコールバック関数が必要なのか

JavaScriptでは、処理の順序やタイミングを制御する場面が多くあります。

特に重要なのが以下の2つです。

  • 非同期処理(時間がかかる処理)
  • イベント処理(ユーザー操作など)

これらは「いつ実行されるか」が不確定なため、コールバック関数が活躍します。

非同期処理でのコールバック関数

JavaScriptはシングルスレッドで動作するため、時間のかかる処理は非同期で実行されます。

setTimeoutの例

console.log("処理開始");

setTimeout(function () {
  console.log("3秒後に実行");
}, 3000);

console.log("処理終了");

実行結果

処理開始
処理終了
(3秒後)
3秒後に実行

このように、後から実行される処理としてコールバック関数が使われています。

イベント処理でのコールバック関数

ユーザーの操作(クリックや入力)に応じて処理を行う場合にも、コールバック関数が使われます。

クリックイベントの例

document.getElementById("btn").addEventListener("click", function () {
  console.log("ボタンがクリックされた");
});

このコードでは、「クリックされたとき」に実行される関数がコールバック関数です。

配列メソッドとコールバック関数

配列操作でもコールバック関数は頻繁に使われます。

forEachの例

const numbers = [1, 2, 3];

numbers.forEach(function (num) {
  console.log(num);
});

配列の各要素に対して処理を行う際に、コールバック関数が活用されています。

※forEachについては
👉「JavaScriptのforEachとは?配列ループの基本」も参照すると理解が深まります。

コールバック関数の書き方(アロー関数)

コールバック関数は、アロー関数でより簡潔に書くことができます。

const numbers = [1, 2, 3];

numbers.forEach((num) => {
  console.log(num);
});

さらに短く書くことも可能です。

numbers.forEach(num => console.log(num));

※アロー関数については
👉「JavaScriptのアロー関数とは?基本と使い方」もあわせて確認することが推奨されます。

コールバック地獄(Callback Hell)とは

コールバック関数を多用すると、コードがネストして読みにくくなる問題があります。

悪い例

setTimeout(function () {
  console.log("1回目");

  setTimeout(function () {
    console.log("2回目");

    setTimeout(function () {
      console.log("3回目");
    }, 1000);

  }, 1000);

}, 1000);

このようにネストが深くなる状態を「コールバック地獄」と呼びます。

解決方法(Promise・async/await)

コールバック地獄を解決するために、以下の方法が使われます。

  • Promise
  • async / await

Promiseの例

function wait(ms) {
  return new Promise(function (resolve) {
    setTimeout(resolve, ms);
  });
}

wait(1000)
  .then(function () {
    console.log("1回目");
    return wait(1000);
  })
  .then(function () {
    console.log("2回目");
    return wait(1000);
  })
  .then(function () {
    console.log("3回目");
  });

コールバック関数の注意点

関数を「実行」せず「渡す」

誤りやすいポイントとして、関数を実行してしまうケースがあります。

// ❌ 間違い
mainFunction(subFunction());

// ✅ 正しい
mainFunction(subFunction);

可読性を意識する

コールバック関数が増えると、コードが複雑になります。
適切に関数を分割することが重要です。

まとめ

コールバック関数は、JavaScriptにおける重要な仕組みです。

  • 関数を引数として渡す仕組み
  • 非同期処理やイベント処理で活用される
  • 配列操作でも頻繁に使用される
  • ネストが深くなると可読性が低下する

基本を理解することで、より高度な非同期処理(Promise・async/await)への理解もスムーズになります。

関連記事

これらの記事をあわせて読むことで、JavaScriptの理解をより体系的に深めることができます。