高階関数

関数を引数に取る、または関数を返す関数で、関数型プログラミングの基本概念

関数型プログラミングJavaScript

高階関数とは

高階関数 (Higher-Order Function) は、関数を引数に取る、または関数を返す関数である。JavaScript の mapfilterreduce が代表例で、関数型プログラミングの基本概念だ。

関数を引数に取る

// map: 各要素を変換
const names = users.map(user => user.name);

// filter: 条件に合う要素を抽出
const adults = users.filter(user => user.age >= 18);

// reduce: 集約
const total = orders.reduce((sum, order) => sum + order.amount, 0);

// sort: 比較関数を渡す
const sorted = users.sort((a, b) => a.age - b.age);

関数を返す

// クロージャ: 外側の変数を記憶する関数を返す
function createMultiplier(factor: number) {
  return (value: number) => value * factor;
}

const double = createMultiplier(2);
const triple = createMultiplier(3);
double(5); // 10
triple(5); // 15

実用的なパターン

デバウンス

function debounce<T extends (...args: any[]) => void>(fn: T, delay: number): T {
  let timer: ReturnType<typeof setTimeout>;
  return ((...args: any[]) => {
    clearTimeout(timer);
    timer = setTimeout(() => fn(...args), delay);
  }) as T;
}

const search = debounce((query: string) => fetchResults(query), 300);

パイプライン

const pipe = <T>(...fns: ((arg: T) => T)[]) =>
  (value: T) => fns.reduce((acc, fn) => fn(acc), value);

const process = pipe(
  (s: string) => s.trim(),
  (s: string) => s.toLowerCase(),
  (s: string) => s.replace(/\s+/g, '-'),
);

process('  Hello World  '); // 'hello-world'

Array メソッドのチェーン

const result = orders
  .filter(o => o.status === 'completed')
  .map(o => ({ ...o, total: o.items.reduce((s, i) => s + i.price, 0) }))
  .sort((a, b) => b.total - a.total)
  .slice(0, 10);

React での高階関数

// useCallback: 関数をメモ化する高階関数
const handleClick = useCallback((id: string) => {
  deleteItem(id);
}, [deleteItem]);

// Array.map でコンポーネントをレンダリング
{items.map(item => <ListItem key={item.id} item={item} />)}

for ループとの比較

観点 for ループ 高階関数
可読性 低い (手続き的) 高い (宣言的)
不変性 変数を変更 新しい配列を返す
チェーン 困難 容易
パフォーマンス やや速い やや遅い (中間配列)

より深く学ぶには関連書籍が役立つ。

関連用語