コールバック関数と高階関数のやさしい解説(初心者向け)
プログラミングを始めたばかりでも、ここを理解すると「イベント処理」や「非同期処理」がぐっと分かりやすくなります。難しい言葉はかみ砕いて、例題で手を動かしながら覚えていきましょう。
まずは全体像
- 関数は“値”として扱える:
関数は数字や文字と同じように、変数に入れたり、ほかの関数に渡したり、戻り値として返したりできます。 - 高階関数:
「関数を受け取ったり返したりする関数」。関数を“操作する関数”だと思ってOK。 - コールバック関数:
「引数として渡され、あとで呼び出される関数」。イベントが起きたとき、時間が経ったときなど“タイミングが来たら実行される”役目。
キモは「流れの分業」
- 処理の本体(何をするか)とタイミングや繰り返し(いつ・どのくらいするか)を分けて考えるために、関数を渡します。
- メリット:
- 柔軟: 何をするかだけ差し替えられる
- 再利用: 同じ“枠”に違う“中身”を入れて使い回せる
- 読みやすい: 役割が分かれてコードが整理される
例題で理解する
例題1: 関数を変数に入れて使う
const sayPrice = function(price) {
console.log("トマトの値段は " + price + "円です。");
};
sayPrice(120);
JavaScript- ポイント:
関数も値だから、constに入れてあとで呼べる。
例題2: 関数を“渡して”使う(高階関数 + コールバック)
function withTomatoPrice(price, callback) {
const name = "トマト";
// “いつ呼ぶか”はこの関数が決める
callback(name, price);
}
function showPrice(name, price) {
console.log(name + "の値段は " + price + "円です。");
}
withTomatoPrice(150, showPrice);
JavaScript- ポイント:
withTomatoPriceは“呼ぶタイミングを管理”、showPriceは“何をするかを定義”。
例題3: 無名関数・アロー関数を直接渡す
withTomatoPrice(180, (name, price) => {
console.log(`${name}の値段は ${price}円です。`);
});
JavaScript- ポイント:
一度しか使わない処理はその場で書くとスッキリ。
例題4: 非同期処理(時間が経ってから呼ぶ)
console.log("Good Morning.");
setTimeout(() => {
console.log("Bye."); // 2秒後に表示
}, 2000);
console.log("How are you?");
JavaScript- ポイント:
setTimeoutは“2秒後にこの関数を呼んでね”という高階関数。待っている間も他のコードは進む。
例題5: 配列の処理を任せる(map, filter)
const prices = [100, 200, 300];
// 10%値上げ後の価格を作る
const up10 = prices.map(p => Math.round(p * 1.1));
// 200円以上だけを残す
const over200 = up10.filter(p => p >= 200);
console.log(up10); // [110, 220, 330]
console.log(over200); // [220, 330]
JavaScript- ポイント:
mapやfilterは高階関数。“各要素に何をするか”だけコールバックで渡す。
よくあるつまずき
- thisが変わる:
アロー関数はthisを外側から引き継ぐ。通常のfunctionは呼び方でthisが変わる。初心者は“イベント内はアロー関数で書く”か“thisを使わない”から始めると安全。 - 引数の数が合わない:
コールバックに渡される引数は“呼ぶ側”が決める。受け取り側のパラメータ数が多すぎる/少なすぎると意図通りに動かないことがある。 - 非同期の順序誤解:
setTimeoutやイベントは“後で”呼ばれる。書いた順番=実行順ではないことに注意。
練習問題
練習1: 何をするかを差し替える
- 課題: 値段と商品名を受け取り、表示方法をコールバックで変えられる関数
withItemを作る。 - ヒント:
function withItem(name, price, callback) {
callback(name, price);
}
// 1) 普通のテキスト
withItem("りんご", 120, (n, p) => {
console.log(`${n}は${p}円`);
});
// 2) 税込表示(10%)
withItem("りんご", 120, (n, p) => {
const taxIn = Math.round(p * 1.1);
console.log(`${n}は税込${taxIn}円`);
});
JavaScript練習2: 繰り返しと処理内容を分ける
- 課題: 配列の各要素に対して“何をするか”をコールバックで渡せる
forEachLikeを作る。 - ヒント:
function forEachLike(array, callback) {
for (let i = 0; i < array.length; i++) {
callback(array[i], i, array); // 値, インデックス, 元配列
}
}
forEachLike([10, 20, 30], (value, index) => {
console.log(`#${index}: ${value * 2}`);
});
JavaScript練習3: 後で実行する仕組み
- 課題: “指定秒数後にメッセージを出す”関数
afterを作る。 - ヒント:
function after(ms, callback) {
setTimeout(callback, ms);
}
after(1000, () => console.log("1秒後にこんにちは"));
JavaScript次の一歩(発展)
- エラーハンドリング:
非同期では失敗もある。成功時と失敗時の2つのコールバックを受け取る書き方や、Promise/async/awaitへ進むとより扱いやすくなる。 - イベントリスナー:
element.addEventListener("click", handler)のhandlerがコールバック。UIやブラウザ操作でも同じ考え方。 - 再利用の設計:
“枠(タイミングや繰り返し)”と“中身(処理)”を分ける発想を、関数設計の基本として癖づける。
まとめ
- 関数は値として扱えるから、渡したり返したりできる。
- 高階関数は“関数を受け取る/返す関数”。
- コールバック関数は“あとで呼ぶために渡された関数”。
- 例題で手を動かすと、非同期・イベント・配列処理の理解が一気に進む。
