JavaScript | コールバック関数 と 高階関数

JavaScript JavaScript
スポンサーリンク

コールバック関数と高階関数のやさしい解説(初心者向け)

プログラミングを始めたばかりでも、ここを理解すると「イベント処理」や「非同期処理」がぐっと分かりやすくなります。難しい言葉はかみ砕いて、例題で手を動かしながら覚えていきましょう。


まずは全体像

  • 関数は“値”として扱える:
    関数は数字や文字と同じように、変数に入れたり、ほかの関数に渡したり、戻り値として返したりできます。
  • 高階関数:
    「関数を受け取ったり返したりする関数」。関数を“操作する関数”だと思って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
  • ポイント:
    mapfilter は高階関数。“各要素に何をするか”だけコールバックで渡す。

よくあるつまずき

  • 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やブラウザ操作でも同じ考え方。
  • 再利用の設計:
    “枠(タイミングや繰り返し)”と“中身(処理)”を分ける発想を、関数設計の基本として癖づける。

まとめ

  • 関数は値として扱えるから、渡したり返したりできる。
  • 高階関数は“関数を受け取る/返す関数”。
  • コールバック関数は“あとで呼ぶために渡された関数”。
  • 例題で手を動かすと、非同期・イベント・配列処理の理解が一気に進む。
タイトルとURLをコピーしました