配列メソッド完全ガイド — map・filter・reduceから実務頻出パターンまで
JavaScriptで最も触る機会が多いデータ構造は配列です。 APIのレスポンスを加工する、フォームの入力値をまとめる、UIにリストを表示する——ほぼすべての場面で配列が登場します。
この章では、配列の「メソッド」とは何かという前提から始めて、実務で頻出する map・filter・reduce・find・some・every を用途別に整理します。
学習者map とか filter とか、名前は聞くけど…結局どれをいつ使えばいいのか毎回迷っちゃう。
この章を読めば「変換は map、絞り込みは filter、集約は reduce」のように、やりたいことから逆引きで選べるようになります。
配列メソッドとは — Array インスタンスのメソッドという意味
[1, 2, 3].map(...) のように配列に対して .map() を呼べるのは、配列が Array コンストラクタのインスタンスだからです。
const arr = [1, 2, 3];
console.log(arr instanceof Array); // true
console.log(typeof arr); // "object"(配列もオブジェクトの一種)JavaScriptでは、[] というリテラルで配列を作ると、内部的には new Array() と同等のオブジェクトが生成されます。
そして、すべての Array インスタンスは Array.prototype というオブジェクトからメソッドを継承しています。
// .map() は配列自体が持っているのではなく、Array.prototype から借りている
console.log(arr.hasOwnProperty('map')); // false
console.log(Array.prototype.hasOwnProperty('map')); // trueつまり arr.map(...) と書いたとき、JavaScriptは以下の順序でメソッドを探しています。
arr自身にmapプロパティがあるか → ないarrのプロトタイプ(Array.prototype)にmapがあるか → ある → これを使う
これが「配列メソッドは Array インスタンスのメソッド」という意味です。
配列っぽく見えるが Array インスタンスではないもの(例: document.querySelectorAll() の戻り値である NodeList)では、そのままでは .map() が使えません。
const nodes = document.querySelectorAll('div');
// nodes.map(...) → TypeError: nodes.map is not a function
// Array.from() で本物の配列に変換すれば使える
Array.from(nodes).map((node) => node.textContent);この前提を押さえたうえで、実務で特に使用頻度の高いメソッドを見ていきます。
map — 各要素を変換して新しい配列を作る

map は配列の各要素にコールバック関数を適用し、その戻り値で構成された新しい配列を返します。
元の配列は変更されません(非破壊)。
const numbers = [1, 2, 3, 4, 5];
const doubled = numbers.map((n) => n * 2);
console.log(doubled); // [2, 4, 6, 8, 10]
console.log(numbers); // [1, 2, 3, 4, 5](元の配列はそのまま)コールバックの引数
コールバックは最大3つの引数を受け取ります。
| 引数 | 意味 |
|---|---|
第1引数 element | 現在処理している要素 |
第2引数 index(省略可) | 現在のインデックス(0始まり) |
第3引数 array(省略可) | 元の配列そのもの |
const result = ['a', 'b', 'c'].map((element, index, array) => {
// element: 現在の要素("a", "b", "c")
// index: 現在のインデックス(0, 1, 2)
// array: 元の配列自体
return `${index}: ${element}`;
});
// ["0: a", "1: b", "2: c"]実務では第1引数だけ使うケースがほとんどです。第2引数の index はリスト表示の key 生成などで使うことがあります。
この (element, index, array) という3引数のコールバックは、map だけでなく filter・find・findIndex・some・every でも共通です。各メソッドで違うのは「コールバックの戻り値をどう扱い、最終的に何を返すか」だけ、と捉えると一気に整理できます。
実務パターン: APIレスポンスの整形
// APIから返ってきたユーザーデータ
const users = [
{ id: 1, first_name: '太郎', last_name: '田中' },
{ id: 2, first_name: '花子', last_name: '佐藤' },
];
// フロントで使いやすい形に変換
const displayUsers = users.map((user) => ({
id: user.id,
fullName: `${user.last_name} ${user.first_name}`,
}));
// [{ id: 1, fullName: "田中 太郎" }, { id: 2, fullName: "佐藤 花子" }]map を使うべきでない場面
map は「変換した新しい配列が欲しいとき」に使います。
戻り値を使わずに副作用(ログ出力、DOM操作など)だけが目的なら forEach を使ってください。
// ❌ mapの戻り値を捨てている — forEachを使うべき
users.map((user) => {
console.log(user.name);
});
// ⭕
users.forEach((user) => {
console.log(user.name);
});filter — 条件に合う要素だけを残す
filter はコールバックが true を返した要素だけで構成された新しい配列を返します。
元の配列は変更されません。
const numbers = [1, 2, 3, 4, 5, 6];
const evens = numbers.filter((n) => n % 2 === 0);
console.log(evens); // [2, 4, 6]実務パターン: 検索フィルタリング
const products = [
{ name: 'ノートPC', price: 120000, inStock: true },
{ name: 'マウス', price: 3000, inStock: true },
{ name: 'キーボード', price: 15000, inStock: false },
{ name: 'モニター', price: 45000, inStock: true },
];
// 在庫ありで1万円以上の商品
const result = products.filter((p) => p.inStock && p.price >= 10000);
// [{ name: "ノートPC", ... }, { name: "モニター", ... }]filter + map のチェーン
filter で絞り込んでから map で変換する、というチェーンは実務で非常によく書きます。
// 在庫あり商品の名前だけを取得
const inStockNames = products.filter((p) => p.inStock).map((p) => p.name);
// ["ノートPC", "マウス", "モニター"]該当なしの場合
条件に合う要素がなければ空配列 [] が返ります。null や undefined ではありません。
const result = [1, 2, 3].filter((n) => n > 10);
console.log(result); // []
console.log(result.length); // 0reduce — 配列を1つの値にまとめる
reduce は配列の各要素を順に処理し、最終的に1つの値に集約します。
合計値、オブジェクト、別の配列など、あらゆる形に集約できる汎用性の高いメソッドです。
const numbers = [1, 2, 3, 4, 5];
const sum = numbers.reduce((accumulator, current) => {
return accumulator + current;
}, 0);
// 0 + 1 + 2 + 3 + 4 + 5 = 15
学習者reduce だけ急に難しい…!accumulator って何者…?
先生accumulator(アキュムレータ)は「途中経過を入れておく箱」。要素を1つ処理するたびに箱の中身を更新して、最後にその箱を返す——そうイメージすると一気にわかりやすくなるよ。
引数の構造
array.reduce((accumulator, currentValue, index, array) => {
// accumulator: 前回のコールバックの戻り値(初回は初期値)
// currentValue: 現在の要素
return nextAccumulator;
}, initialValue);
// ^^^^^^^^^^^^^ 第2引数: 初期値(省略可能だが、常に指定するのが安全)初期値は必ず指定する
初期値を省略すると、配列の最初の要素が初期値として使われます。
空配列に対して初期値なしで reduce を呼ぶと TypeError になるため、初期値は常に指定するのが安全です。
// ❌ 空配列でエラー
[].reduce((acc, cur) => acc + cur);
// TypeError: Reduce of empty array with no initial value
// ⭕ 初期値を指定すれば空配列でも安全
[].reduce((acc, cur) => acc + cur, 0); // 0実務パターン: グルーピング
const orders = [
{ product: 'PC', category: 'electronics' },
{ product: 'シャツ', category: 'clothing' },
{ product: 'マウス', category: 'electronics' },
{ product: 'パンツ', category: 'clothing' },
];
const grouped = orders.reduce((acc, order) => {
const key = order.category;
if (!acc[key]) {
acc[key] = [];
}
acc[key].push(order);
return acc;
}, {});
// {
// electronics: [{ product: "PC", ... }, { product: "マウス", ... }],
// clothing: [{ product: "シャツ", ... }, { product: "パンツ", ... }]
// }なお、このグルーピングは ES2024 で追加された Object.groupBy でより簡潔に書けるようになりました。
const grouped = Object.groupBy(orders, (order) => order.category);reduce を使いすぎない
reduce は汎用的すぎるがゆえに、何をしているか読みにくくなりがちです。
map + filter で書ける処理を無理に reduce で書く必要はありません。
// ❌ reduceで書いているが、やっていることはfilter + map
const result = numbers.reduce((acc, n) => {
if (n > 3) acc.push(n * 2);
return acc;
}, []);
// ⭕ 意図が明確
const result = numbers.filter((n) => n > 3).map((n) => n * 2);reduce の出番は「合計」「グルーピング」「オブジェクトへの変換」など、map / filter では表現できない集約処理です。
find — 条件に合う最初の1つを取得
find はコールバックが true を返した最初の要素を返します。
見つからなければ undefined です。
const users = [
{ id: 1, name: '太郎' },
{ id: 2, name: '花子' },
{ id: 3, name: '次郎' },
];
const user = users.find((u) => u.id === 2);
console.log(user); // { id: 2, name: "花子" }
const notFound = users.find((u) => u.id === 99);
console.log(notFound); // undefinedfilter との違い
| メソッド | 戻り値 | 見つからない場合 |
|---|---|---|
find | 最初にマッチした要素そのもの | undefined |
filter | マッチしたすべての要素の配列 | [](空配列) |
「1つだけ欲しい」なら find、「全部欲しい」なら filter です。
findIndex
要素ではなくインデックスが欲しい場合は findIndex を使います。見つからなければ -1 を返します。
const index = users.findIndex((u) => u.id === 2);
console.log(index); // 1some — 1つでも条件を満たすか
some はコールバックが true を返す要素が1つでもあれば true を返します。
全要素が false なら false です。
const numbers = [1, 3, 5, 8, 9];
const hasEven = numbers.some((n) => n % 2 === 0);
console.log(hasEven); // true(8が偶数)実務パターン: 権限チェック
const userRoles = ['editor', 'viewer'];
const canEdit = userRoles.some((role) => role === 'editor' || role === 'admin');
console.log(canEdit); // true短絡評価する
some は true を返す要素を見つけた時点で残りの要素を処理せずに終了します。大きな配列でもパフォーマンス上の問題になりにくいです。
every — すべてが条件を満たすか
every はすべての要素でコールバックが true を返した場合に true を返します。
1つでも false があれば即座に false を返します。
const ages = [20, 25, 30, 18];
const allAdults = ages.every((age) => age >= 20);
console.log(allAdults); // false(18が条件を満たさない)実務パターン: フォームバリデーション
const fields = [
{ name: 'email', value: 'test@example.com', valid: true },
{ name: 'password', value: 'abc', valid: false },
{ name: 'name', value: '太郎', valid: true },
];
const isFormValid = fields.every((field) => field.valid);
console.log(isFormValid); // false(passwordが invalid)空配列に対する every
空配列に対して every は常に true を返します。
これは論理学の「空真」(vacuous truth)に基づく仕様ですが、実務ではバグの原因になりえます。
[].every((x) => x > 0); // true(!)空配列の可能性がある場合は、事前に length をチェックしてください。
メソッドの使い分け早見表
| やりたいこと | メソッド | 戻り値 |
|---|---|---|
| 各要素を変換する | map | 新しい配列 |
| 条件で絞り込む | filter | 新しい配列 |
| 1つの値にまとめる | reduce | 任意の値 |
| 条件に合う最初の要素 | find | 要素 or undefined |
| 条件に合う最初のインデックス | findIndex | 数値 or -1 |
| 1つでも条件を満たすか | some | boolean |
| すべて条件を満たすか | every | boolean |
よくあるハマりどころ

元の配列を壊すメソッドと壊さないメソッド
この章で扱った map・filter・reduce・find・some・every はすべて非破壊(元の配列を変更しない)です。
一方、以下のメソッドは元の配列を直接変更する(破壊的)ので注意が必要です。
| 破壊的メソッド | 非破壊の代替(ES2023〜) |
|---|---|
sort() | toSorted() |
reverse() | toReversed() |
splice() | toSpliced() |
const arr = [3, 1, 2];
// ❌ 元の配列が変わる
arr.sort();
console.log(arr); // [1, 2, 3](元の配列が変わっている)
// ⭕ 元の配列は変わらない(ES2023)
const sorted = [3, 1, 2].toSorted();map の中で条件分岐しない
map の中で if を使って一部の要素だけ変換するのは、filter + map に分けるべきサインです。
// ❌ mapの中で条件分岐 → undefinedが混じる
const result = numbers.map((n) => {
if (n > 3) return n * 2;
});
// [undefined, undefined, undefined, 8, 10]
// ⭕
const result = numbers.filter((n) => n > 3).map((n) => n * 2);
// [8, 10]ちゃんと使うためのポイント
- 配列メソッドは
Array.prototypeに定義されており、すべての配列インスタンスが継承している mapは変換、filterは絞り込み、reduceは集約——目的に応じて使い分けるfindは最初の1つ、someは1つでもあるか、everyは全部かを判定するreduceは万能だが読みにくくなりがち。map+filterで書けるなら分けた方が明快- 破壊的メソッド(
sort/reverse/splice)と非破壊メソッドの区別を意識する
次の章では、文字列操作と正規表現を取り上げます。実務でよく使うパターンをまとめます。