JavaScriptを学習していると必ず出会う言葉に「コールバック関数」があります。
「関数を別の関数に値として渡す」という少し特殊な仕組みに、最初は戸惑う方も多いのではないでしょうか。
「引数としてどうやって渡せばいいの?」
「アロー関数での書き方を知りたい」
こうした疑問を解決するために、この記事ではJavaScriptのコールバック関数の仕組みをわかりやすく徹底解説します。
基本の書き方はもちろん、引数や戻り値の扱いや、実務で必須となる非同期処理での使いどころまで、具体的なサンプルコードを交えて紹介します。
![]() 執筆者:マヒロ |
|
- OS:Windows 11 / macOS Sequoia
- IDE:Visual Studio / VS Code / IntelliJ IDEA
- その他:Chrome DevTools / 各言語最新安定版
※本メディアでは、上記環境にてコードの動作と情報の正確性を検証済みです。
JavaScriptのコールバック関数とは?仕組みをわかりやすく解説
コールバック関数とは、「他の関数に引数として渡され、その関数の内部で実行される関数」のことです。
JavaScriptにおいて、関数は数値や文字列と同じように「値」として扱うことができます。
これを「第一級オブジェクト」と呼びます。
この性質があるおかげで、関数を別の関数へプレゼントのように渡し、渡された側が「好きなタイミングでその関数を呼び出す」という操作が可能になります。
例えば、あなたがレストランで料理を注文したとしましょう。
料理ができるのをずっと厨房の前で待つのではなく、「料理ができたらテーブルまで持ってきて(実行して)」と店員さんに伝えておき、自分は席で別のことをして待つはずです。
この「料理ができたらやってほしいこと(店員さんに預けた指示)」が、プログラミングにおけるコールバック関数に当たります。
この例は非同期処理(後で行われる処理)のイメージですが、コールバック関数は配列の並び替えやデータの加工といった、同期処理(その場ですぐに行われる処理)でも非常に頻繁に使われます。
コールバック関数の書き方と基本的な使い方
コールバック関数を使いこなすためには、まず「関数を定義する」ことと「関数を引数として渡す」という2つのステップを理解する必要があります。
ここでは、最もシンプルな「挨拶をする関数」を例に、基本的な構造を見ていきましょう。
引数として関数を渡す手順
以下のソースコードは、メインの処理を行う関数に、別の関数を引数として渡して実行する基本的な例です。
// 1. コールバックとして使われる関数を定義
function greet(name) {
console.log("こんにちは、" + name + "さん!");
}
// 2. コールバック関数を受け取って実行する関数を定義
function processUserInput(callback) {
const userName = "田中";
// 受け取った関数(callback)を内部で実行する
callback(userName);
}
// 3. 関数を引数として渡して実行
processUserInput(greet);
実行結果
こんにちは、田中さん!
このソースコードが何を意味しているのかを詳しく紐解いていきましょう。
まず、greet という名前の関数を定義しています。
これは引数 name を受け取ってメッセージを表示するだけのシンプルなものです。
次に processUserInput という関数を定義していますが、ここでのポイントは、引数として callback という名前の変数を受け取っている点です。
最後に processUserInput(greet) と呼び出していますが、ここで greet() ではなく greet と記述していることに注目してください。
括弧をつけずに渡すことで、「関数を実行した結果」ではなく「関数そのもの」を引数として渡しています。
processUserInput の内部に到着した greet 関数は、callback(userName) というコードによって、ようやく実行されることになります。
アロー関数を使ったコールバック関数の書き方
現代のJavaScript開発では、わざわざ事前に名前を付けて関数を定義するのではなく、その場で「アロー関数」を使って使い捨てのコールバック関数を書く手法が、特に短い処理においてよく使われます。
アロー関数を使うことで、コードの記述量を劇的に減らし、処理の内容を直感的に記述できるようになります。
記述を簡略化するメリット
配列のすべての要素に対して処理を行う forEach メソッドを例に、アロー関数でのコールバックの実装を見てみましょう。
const colors = ["赤", "青", "緑"];
// 配列の各要素に対して、その場で定義したアロー関数を実行する
colors.forEach((color) => {
console.log("現在の色は" + color + "です");
});
実行結果
現在の色は赤です
現在の色は青です
現在の色は緑です
forEach メソッドは、配列の要素を一つずつ取り出し、引数として渡されたコールバック関数を実行する命令です。
ここでは、(color) => { ... } というアロー関数を直接 forEach の引数に記述しています。
アロー関数を使うことで function というキーワードを省略でき、非常にスッキリとした見た目になります。
ただし、アロー関数は this を持たないといった特性があるため、メソッドの定義や複雑なイベントハンドラなどでは、従来の function 記法と適切に使い分ける必要があります。
コールバック関数の「引数」と「戻り値」の深い関係
コールバック関数は、単に実行されるだけでなく、メインの関数からデータを受け取ったり(引数)、処理の結果をメインの関数へ返したり(戻り値)することも可能です。
※以下のサンプルは、その場ですぐに実行される「同期的なコールバック」の例です。
内部で値を処理して返す仕組み
以下の例では、計算を行う関数に数値の加工方法(コールバック)を指示し、その結果を受け取る流れを再現しています。
// 計算結果を加工する関数
function calculate(num1, num2, callback) {
const sum = num1 + num2;
// 計算結果をコールバック関数に渡して、加工した結果を受け取る
const result = callback(sum);
return result;
}
// 実行:合計値を「10倍」にして取得する
const finalValue = calculate(5, 3, (total) => {
return total * 10;
});
console.log("最終的な値: " + finalValue);
実行結果
最終的な値: 80
calculate 関数は、2つの数値を足した後に、その合計値 sum を第3引数の callback にパスしています。
呼び出し側では (total) => { return total * 10; } という処理を渡しており、これが実行されることで合計値 8 が 80 に加工されます。
さらに、コールバック関数の中で return された 80 という値は、calculate 関数内の変数 result に格納され、最終的に finalValue へと届けられます。
このように、コールバック関数は「外側から計算ロジックを注入する」役割を果たしており、これによって calculate 関数自体の中身を書き換えることなく、あらゆる計算に使い回せる柔軟なプログラムが実現できます。
非同期処理での使いどころとメリット・デメリット
JavaScriptにおいてコールバック関数が最も威力を発揮するのは、APIからのデータ取得やタイマー処理などの「非同期処理」を行う場面です。
非同期処理(setTimeout)の例
指定した時間(ミリ秒)が経過した後に処理を実行する setTimeout は、典型的な非同期のコールバック活用例です。
console.log("処理を開始します");
// 2秒後にコールバック関数を実行する
setTimeout(() => {
console.log("2秒経過しました(非同期処理)");
}, 2000);
console.log("次の処理を進めます");
実行結果
処理を開始します
次の処理を進めます
2秒経過しました(非同期処理)
ソースコードの動作を詳しく説明します。 setTimeout は、第1引数にコールバック関数を、第2引数に待機時間を取ります。
ここで重要なのは、プログラムが2秒間止まるわけではないという点です。
JavaScriptの内部では「イベントループ」という仕組みによって管理されており、1行目の出力が終わった後、JavaScriptは「2秒後にこの関数を動かしてね」という予約だけをして、すぐに次の行(「次の処理を進めます」)を実行します。
そして、約束の2秒が経過したタイミングでコールバック関数が呼び出されます。
このように「待ち時間」を有効活用できるのが非同期処理の大きなメリットです。
コールバック関数のメリットとデメリット(コールバック地獄)
コールバック関数を使うことで、プログラムに柔軟性を持たせ、非同期処理を効率的に回せるというメリットがあります。
しかし、一方で大きなデメリットも存在します。
それが「コールバック地獄」と呼ばれる現象です。
非同期処理を順番に行いたい場合(Aが終わったらB、Bが終わったらC…)、コールバックの中にさらにコールバックを書くことになり、コードが右側にどんどん深くなってしまいます。
// コールバック地獄のイメージ(非常に読みづらい)
getData((data) => {
saveData(data, (result) => {
sendNotification(result, (status) => {
console.log("すべての処理が完了");
});
});
});
このような深い階層はバグの温床となり、メンテナンスが困難になります。 現在、新規開発では Promise や async/await という仕組みが選ばれることが多いですが、それらも内部的にはコールバックの概念に基づいています。
そのため、まずはコールバック関数の基本をしっかり理解しておくことが、JavaScriptマスターへの最短ルートなのです。
JavaScriptのスキルを活かして年収を上げる方法
以上、JavaScriptのコールバック関数について詳しく解説してきました。
| 年収アップにこだわりたい方 (平均アップ額138万円の実績) | テックゴー |
| 未経験・経験者問わず幅広く探したい方 | ユニゾンキャリア |
| 業界に精通した担当者に相談したい方 | キッカケエージェント |
| ゲーム業界への転職を志望する方 | ファミキャリ |
| エンジニア未経験からキャリアを築く方 | イーチキャリア |



