JavaScriptの高階関数とは?map, filter, reduceを例に解説
生徒
「先生、高階関数って何ですか?なんだか難しそうです…」
先生
「高階関数とは、『関数を引数にしたり、関数を返したりする関数』のことです。簡単に言うと、『関数を操作できる関数』ですね。」
生徒
「関数を引数にするってどういう意味ですか?」
先生
「例えば、関数に別の関数を渡して、その関数の処理を変えたり、実行したりできることです。JavaScriptにはそういう便利な関数がたくさんありますよ。」
生徒
「具体的にはどんなものがあるんですか?」
先生
「有名なのが map、filter、reduce という配列に使う高階関数です。これらを使うと、配列のデータを簡単に加工できますよ。」
1. 高階関数とは?
高階関数(こうかいかんすう)とは、関数を引数に受け取ったり、関数を結果として返したりする関数のことです。プログラミング初心者には少し難しく聞こえますが、要は「関数を扱う関数」と覚えましょう。
JavaScriptでは、関数は「値」として扱えます。なので、他の関数の中に関数を渡したり、戻り値として関数を返すことができます。
例えば:
function sayHello() {
console.log("こんにちは");
}
function executeFunction(func) {
func();
}
executeFunction(sayHello); // こんにちは
ここでは、executeFunctionという関数に、sayHelloという関数を渡して実行しています。
2. mapメソッドとは?
mapは配列の要素を「一つずつ関数で変換して、新しい配列を作る」ための高階関数です。
例えば、数字の配列のすべての値を2倍にしたい時、普通ならループで書きますが、mapなら簡単にできます。
const numbers = [1, 2, 3, 4];
const doubled = numbers.map(function(num) {
return num * 2;
});
console.log(doubled); // [2, 4, 6, 8]
ここで渡している関数は「numを2倍にして返す関数」です。mapはこれを配列の全要素に適用して新しい配列を返します。
3. filterメソッドとは?
filterは配列の要素を「条件に合うものだけ集めて新しい配列を作る」高階関数です。
例えば、数字の配列から偶数だけを取り出したいときに使います。
const numbers = [1, 2, 3, 4, 5, 6];
const evens = numbers.filter(function(num) {
return num % 2 === 0;
});
console.log(evens); // [2, 4, 6]
渡した関数は「偶数かどうか」を判定しています。trueを返した要素だけが残ります。
4. reduceメソッドとは?
reduceは配列の要素を一つにまとめる(例えば合計や積を出す)高階関数です。
例えば、配列の数字を全部足し合わせるときに使います。
const numbers = [1, 2, 3, 4];
const sum = numbers.reduce(function(accumulator, current) {
return accumulator + current;
}, 0);
console.log(sum); // 10
ここで accumulator は「これまでの合計」、current は「今の数字」です。初めの値は 0 で、順番に足しています。
5. まとめて使う例
これらを組み合わせると、配列のデータを便利に加工できます。例えば、数字を2倍にして偶数だけ集めて合計を出す例です。
const numbers = [1, 2, 3, 4, 5];
const result = numbers
.map(num => num * 2)
.filter(num => num % 2 === 0)
.reduce((sum, num) => sum + num, 0);
console.log(result); // 20
まず2倍にして、偶数だけにして、その合計を求めています。
6. 高階関数が初心者におすすめな理由
高階関数を使うことで、ループの処理を短く簡潔に書けて、コードの意味もわかりやすくなります。
例えば、forループを使って書くと何十行にもなる処理が、たった数行で書けることもあります。
また、関数に名前をつけて渡せるので、処理の内容がはっきりし、バグも見つけやすくなります。
7. まとめ
JavaScriptの高階関数 map、filter、reduce は配列を操作する強力なツールです。これらを使うことで、データの変換や抽出、集計が簡単にできます。
初めは少し難しいかもしれませんが、何度もコードを書いて慣れていきましょう!
まとめ
ここまでJavaScriptにおける「高階関数」の基礎から、代表的なメソッドであるmap、filter、reduceの具体的な使い方について解説してきました。高階関数と聞くと、数学的な響きがあり「難しそう」と身構えてしまう方も多いかもしれませんが、その実態は「関数を値として扱う」というJavaScriptの柔軟性を最大限に活かした便利な仕組みに過ぎません。
高階関数のメリットを再確認しよう
なぜ現場のエンジニアが高階関数を好んで使うのか、その理由は主に3つあります。
- コードの可読性が飛躍的に向上する: 従来の
for文やwhile文によるループ処理は、ループ変数の管理(iを1ずつ増やすなど)が必要で、記述が煩雑になりがちでした。高階関数なら「何をしたいか」という意図が明確になります。 - 副作用の少ない安全なプログラミング:
mapやfilterは、元の配列(オリジナルデータ)を直接書き換えずに、新しい配列を生成して返します。これにより、予期せぬデータの破壊を防ぐことができます。 - 処理の共通化と再利用: 特定のロジックを関数として切り出し、それを別の関数に注入することで、コードの重複を減らすことができます。
配列操作の三種の神器:使い分けのポイント
今回学んだ3つのメソッドの使い分けを整理しておきましょう。
| メソッド名 | 主な役割 | 戻り値のイメージ |
|---|---|---|
| map | 全要素を一定のルールで変換する | 要素数は同じで、中身が変化した新しい配列 |
| filter | 条件に一致するものだけを抽出する | 条件に合う要素だけを詰め直した新しい配列 |
| reduce | 全要素を計算して一つに集約する | 数値、文字列、あるいは一つのオブジェクトなど |
実践的なサンプルプログラム:ユーザーデータの加工
より実践に近い形として、TypeScriptを用いて「ユーザーリストから特定の条件の人を抽出し、その名前だけを整形して取得する」という処理を書いてみましょう。実務でも非常によく使うパターンです。
interface User {
id: number;
name: string;
age: number;
isActive: boolean;
}
const users: User[] = [
{ id: 1, name: "田中", age: 25, isActive: true },
{ id: 2, name: "佐藤", age: 30, isActive: false },
{ id: 3, name: "鈴木", age: 35, isActive: true },
{ id: 4, name: "伊藤", age: 20, isActive: true },
];
// 30歳未満で、かつアクティブなユーザーの名前だけを取り出して、「様」をつける
const activeYoungUserNames = users
.filter((user: User) => user.age < 30 && user.isActive)
.map((user: User) => `${user.name} 様`);
console.log(activeYoungUserNames);
このコードの実行結果は以下のようになります。
[ "田中 様", "伊藤 様" ]
このように、メソッドチェーン(ドットでつなげる書き方)を利用することで、複雑なデータ加工も上から下へと流れるような直感的な記述が可能になります。これがJavaScriptのモダンな書き方の基本となります。
さらに一歩進んだ理解のために
高階関数をマスターすると、ReactやVue.jsといったモダンなフロントエンドフレームワークの学習も非常にスムーズになります。例えばReactでは、リスト表示を行う際にmap関数を使ってコンポーネントを繰り返し生成するのが標準的な手法です。
最初は引数に渡す「コールバック関数」の書き方に戸惑うかもしれませんが、アロー関数(() => {})とセットで覚えてしまうのが近道です。まずは小さな配列で何度も練習し、ブラウザのコンソールで結果を確認する習慣をつけましょう。
生徒
「先生、今回のまとめで高階関数の凄さがよくわかりました!特にメソッドをドットでつないでいく『メソッドチェーン』、見た目がすごくスッキリしていてかっこいいですね。」
先生
「そうでしょう!コードが短くなるだけでなく、後から読んだ時に『何を抽出して、何を変換しているのか』がひと目で分かるのが最大のメリットなんですよ。for文だと、どうしても途中でどんな処理をしているか追いかけづらくなりますからね。」
生徒
「確かに、filterなら『選別しているんだな』ってすぐに分かります。でも、reduceだけはまだ少し使い所が難しそうです。合計を出す以外にも使い道はありますか?」
先生
「鋭いですね。reduceは実は一番万能なんです。例えば、配列をオブジェクト形式に変換したり、多次元配列を平坦化(フラットにする)したりすることも可能です。最初は合計計算から慣れていけば十分ですが、複雑な集計が必要になった時に思い出すと武器になりますよ。」
生徒
「なるほど。まずはmapとfilterを完璧に使いこなせるように練習してみます。TypeScriptでの型定義も意識すると、よりバグが減りそうですね!」
先生
「その意気です。型を意識することで、高階関数の中で扱っている要素が何なのかが明確になります。JavaScriptの柔軟な特性を理解して、よりスマートなエンジニアを目指しましょう。応援していますよ!」
生徒
「はい!ありがとうございます。どんどんコードを書いて体で覚えていきます!」