高階関数とは何か
高階関数は「関数を“引数として受け取る”、または“関数を返す”関数」のことです。関数を値として扱えることで、ロジックの差し替え・再利用・合成が簡単になります。ここが重要です:ES6+ ではアロー関数、デフォルト引数、残余引数、レキシカル this がそろい、短く安全に高階関数を使えるようになりました。
// 関数を“受け取る”高階関数
function process(rows, mapFn) {
return rows.map(mapFn); // mapFn は外から注入
}
// 関数を“返す”高階関数
const makeAdder = x => y => x + y;
const add10 = makeAdder(10);
console.log(add10(5)); // 15
JavaScriptES6+で相性が良くなった理由
アロー関数でコールバックが短くなる
アロー関数は「(引数) => 式」の形で、暗黙の return を使えば1行で意図が伝わります。ここが重要です:高階関数に渡すコールバックが短く、ノイズ(function/return)が減ります。
const labels = rows => rows.map(r => `${r.id}:${r.name.trim()}`);
JavaScriptレキシカルthisで「文脈」が安定する
アロー関数は this を“定義場所”に固定します。高階関数へコールバックを渡しても this 迷子になりません。ここが重要です:クラスやオブジェクトの内部状態を扱うコールバックでも安全です。
class Counter {
constructor() { this.value = 0; }
start() { setInterval(() => { this.value++; }, 1000); } // this が固定
}
JavaScriptデフォルト引数・残余引数で柔軟なインターフェース
高階関数の“可変部分”に既定値や可変長を与えて、呼び出し側を短くできます。ここが重要です:よくある使い方を既定にし、必要なときだけ上書きさせる。
function transform(rows, mapFn = r => r, ...extras) {
return rows.map(r => mapFn(r, ...extras));
}
JavaScript配列メソッドは高階関数の宝庫
map・filter・reduce(鉄板の3兄弟)
配列メソッドは「関数を渡して処理を委ねる」典型です。ここが重要です:変換は map、絞り込みは filter、集計は reduce に役割分担すると読みやすくなります。
const rows = [
{ id: 1, active: true, price: 100 },
{ id: 2, active: false, price: 200 },
{ id: 3, active: true, price: 300 },
];
const view = rows
.filter(r => r.active)
.map(r => ({ id: r.id, tax: Math.round(r.price * 0.1) }));
const total = rows.reduce((sum, r) => sum + r.price, 0);
JavaScriptsort・flatMap(ひと味違う応用)
sort は比較関数を渡す高階関数、flatMap は map の結果を平坦化します。ここが重要です:比較・展開の戦略をコールバックで注入する。
// sort:比較関数を差し替え可能
const byPriceAsc = (a, b) => a.price - b.price;
const sorted = [...rows].sort(byPriceAsc);
// flatMap:変換しつつ配列を平坦化
const tokens = ["a b", "c", "d e"].flatMap(s => s.split(" ")); // ["a","b","c","d","e"]
JavaScript高階関数を自分で設計する
関数を受け取るAPI(戦略の差し替え)
“可変部分”をコールバックにして差し替え可能にします。ここが重要です:テスト容易性と拡張性が上がる設計になります。
function processRows(rows, mapFn, filterFn = () => true) {
return rows.filter(filterFn).map(mapFn);
}
// 用途に応じて戦略だけ差し替える
const cards = processRows(
rows,
r => `${r.id}:${r.price}`,
r => r.active
);
JavaScript関数を返すAPI(カリー化・部分適用)
設定を先に固定して、あとでデータだけ渡せる関数を返します。ここが重要です:複数箇所で同じ設定を使うときに便利です。
const makeTaxMapper = (rate = 0.1, round = Math.round) =>
row => ({ id: row.id, priceWithTax: round(row.price * (1 + rate)) });
const map10 = makeTaxMapper(0.1);
const view2 = rows.map(map10);
JavaScriptよくある落とし穴と対策
this を失う呼び出し
メソッドを直接コールバックに渡すと this が消えます。ここが重要です:アローで包むか bind で固定する。
const view = { id: 42, render() { console.log(this.id); } };
setTimeout(() => view.render(), 0); // OK
// setTimeout(view.render, 0); // NG
JavaScript無理な1行化で可読性低下
暗黙の return に詰め込みすぎると意図が伝わりません。複雑なら波括弧+return に切り替える。
const calc = x => {
const base = x > 0 ? x * 2 : x / 2;
const bonus = Math.max(0, x - 10);
return (base + bonus) | 0;
};
JavaScript副作用の扱い
高階関数は“純粋な変換”に向いています。副作用(ログ・DOM操作)は分離し、変換・集計のコールバックは可能な限り純粋に。
// 変換は純粋に、描画は別フェーズで
const view3 = rows.map(r => ({ id: r.id, price: r.price * 2 }));
view3.forEach(v => console.log(v));
JavaScript例題で理解を固める
// 1) フィルタ+マップ:外部設定を関数として注入
const applyTax = (rate = 0.1, round = Math.round) =>
r => ({ id: r.id, priceWithTax: round(r.price * (1 + rate)) });
const onlyActive = r => r.active;
const result = rows.filter(onlyActive).map(applyTax(0.08, Math.ceil));
// 2) 検索クエリビルダー:関数を返して部分適用
const makeQuery = base => params =>
`${base}?${new URLSearchParams(params)}`;
const search = makeQuery("/search");
console.log(search({ q: "js", page: 2 }));
// 3) 安全なパイプライン:関数を合成して段階処理
const pipe = (...fns) => x => fns.reduce((v, f) => f(v), x);
const trim = s => s.trim();
const lower = s => s.toLowerCase();
const toSlug = s => s.replace(/\s+/g, "-");
const slugify = pipe(trim, lower, toSlug);
console.log(slugify(" Hello World ")); // "hello-world"
JavaScriptまとめ
高階関数の核心は「ロジックを“関数の受け渡し”で差し替え・合成できる」ことです。ES6+ はアロー関数で短く、レキシカル this で安全に、デフォルト引数・残余引数で柔軟に設計できます。配列メソッドを軸に、関数を受け取る・返すAPIを組み、this 失い・副作用・過剰な1行化を避ける。この指針を徹底すれば、初心者でも直感的で保守しやすい関数設計を実現できます。

