- JavaScript
JavaScript 配列 操作 一覧|全メソッド早見表とNode 22実行結果
JavaScriptの配列操作は、Array のメソッド(push・find・map・toSorted など)と、スプレッド構文 ...、Object.groupBy などの組み合わせで書けます。 選ぶときに一番大事なのは、そのメソッドが「元の配列を変える(破壊的)」か「新しい配列を返す(非破壊)」かです。
この記事では、配列のメソッドを目的別(作成・追加・削除・検索・判定・並べ替え・変換・結合・集計・コピー)の一覧表に「破壊的か」「戻り値」「ES版」をつけて整理し、すべての例をNode.js 22(v22.22.2)で実行した出力つきで紹介します。ES2023〜ES2026の新メソッドや、sort の数値の並び、NaN の検索、浅いコピーのつまずきも実行結果で確認します。
JavaScript 配列操作の早見表(目的別・全メソッド)
「破壊的」が「する」のメソッドは元の配列を書き換えます。ES版はECMAScriptの版(ES1〜ES5は2009年までの版)です。
| 目的 | メソッド | 破壊的 | 戻り値 | ES版 |
|---|---|---|---|---|
| 作成 | Array.from(反復可能, 変換) |
- | 新しい配列 | ES2015 |
Array.of(...要素) |
- | 新しい配列 | ES2015 | |
Array.fromAsync(非同期反復可能) |
- | Promise(配列) | ES2026 | |
fill(値, 開始, 終了) |
する | 元の配列 | ES2015 | |
| 追加 | push(...要素)(末尾) |
する | 新しい長さ | ES3 |
unshift(...要素)(先頭) |
する | 新しい長さ | ES3 | |
| 削除 | pop()(末尾) |
する | 取り出した要素 | ES3 |
shift()(先頭) |
する | 取り出した要素 | ES3 | |
| 追加・削除・置換 | splice(位置, 個数, ...追加) |
する | 削除した要素の配列 | ES3 |
toSpliced(位置, 個数, ...追加) |
しない | 新しい配列 | ES2023 | |
with(位置, 値)(1つ置き換え) |
しない | 新しい配列 | ES2023 | |
| 検索 | find(条件) / findLast(条件) |
しない | 要素 or undefined |
ES2015 / ES2023 |
findIndex(条件) / findLastIndex(条件) |
しない | 位置 or -1 |
ES2015 / ES2023 | |
indexOf(値) / lastIndexOf(値) |
しない | 位置 or -1 |
ES5 | |
at(位置)(負の数で末尾から) |
しない | 要素 | ES2022 | |
| 判定 | includes(値) |
しない | 真偽値 | ES2016 |
some(条件) / every(条件) |
しない | 真偽値 | ES5 | |
Array.isArray(値) |
- | 真偽値 | ES5 | |
| 並べ替え | sort(比較関数) / reverse() |
する | 元の配列 | ES1 |
toSorted(比較関数) / toReversed() |
しない | 新しい配列 | ES2023 | |
copyWithin(先, 開始, 終了) |
する | 元の配列 | ES2015 | |
| 変換 | map(関数) |
しない | 新しい配列 | ES5 |
filter(条件) |
しない | 新しい配列 | ES5 | |
flat(深さ) / flatMap(関数) |
しない | 新しい配列 | ES2019 | |
| 結合・分割 | concat(...配列) |
しない | 新しい配列 | ES3 |
slice(開始, 終了) |
しない | 新しい配列 | ES3 | |
join(区切り) |
しない | 文字列 | ES1 | |
| 集計 | reduce(関数, 初期値) / reduceRight |
しない | 集計結果 | ES5 |
Object.groupBy(配列, 関数) |
- | オブジェクト | ES2024 | |
Map.groupBy(配列, 関数) |
- | Map | ES2024 | |
| 反復 | forEach(関数) |
しない | undefined |
ES5 |
keys() / values() / entries() |
しない | イテレーター | ES2015 | |
| コピー | [...arr] / arr.slice() / Array.from(arr) |
しない | 浅いコピー | ES2015 / ES3 |
structuredClone(arr) |
- | 深いコピー | HTML標準 |
破壊的なのは push pop shift unshift splice sort reverse fill copyWithin の9つだけです。このうち sort・reverse・splice には、ES2023で非破壊版の toSorted・toReversed・toSpliced が追加されました。
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「JavaScript 配列 操作 一覧|全メソッド早見表とNode 22実行結果」
配列を作る:Array.from・Array.of・fill
連番や決まった長さの配列は Array.from({ length: n }, 関数) で作ります。 以下、コメントの // → はNode.js v22.22.2での実際の出力です。
console.log(Array.from({ length: 3 }, (_, i) => i * 10)); // → [ 0, 10, 20 ]
console.log(Array.from("abc")); // → [ 'a', 'b', 'c' ]
console.log(Array.from(new Set([1, 1, 2]))); // → [ 1, 2 ]
console.log(Array.of(7), Array(7).length); // → [ 7 ] 7
console.log(new Array(3).fill(0)); // → [ 0, 0, 0 ]
console.log([...Array(3).keys()]); // → [ 0, 1, 2 ]
Array(7) は「長さ7の空の配列」、Array.of(7) は「7が1つ入った配列」です。
fill にオブジェクトや配列を渡すと、全要素が同じものを指します。
const grid = Array(2).fill([]);
grid[0].push("x");
console.log(grid); // → [ [ 'x' ], [ 'x' ] ]
const grid2 = Array.from({ length: 2 }, () => []);
grid2[0].push("x");
console.log(grid2); // → [ [ 'x' ], [] ]
要素ごとに別の配列・オブジェクトが必要なときは Array.from の関数で毎回作ります。
追加・削除:push・pop・shift・unshift・splice
const a = [1, 2, 3];
console.log(a.push(4), a); // → 4 [ 1, 2, 3, 4 ]
console.log(a.unshift(0), a); // → 5 [ 0, 1, 2, 3, 4 ]
console.log(a.pop(), a); // → 4 [ 0, 1, 2, 3 ]
console.log(a.shift(), a); // → 0 [ 1, 2, 3 ]
const b = ["a", "b", "c", "d"];
console.log(b.splice(1, 2, "X"), b); // → [ 'b', 'c' ] [ 'a', 'X', 'd' ]
push / unshift の戻り値は「追加後の長さ」、pop / shift は「取り出した要素」、splice は「削除した要素の配列」です。新しい配列が欲しいときは [...arr, x] や [x, ...arr] を使います。
元の配列を変えない新メソッド(ES2023):toSorted・toReversed・toSpliced・with
ES2023で追加された4つは、破壊的メソッドの「コピーを返す版」です。 Reactのstateのように元を書き換えたくない場面で便利です。
const nums = [3, 1, 10, 2];
console.log(nums.toSorted((x, y) => x - y)); // → [ 1, 2, 3, 10 ]
console.log(nums.toReversed()); // → [ 2, 10, 1, 3 ]
console.log(nums.toSpliced(1, 1)); // → [ 3, 10, 2 ]
console.log(nums.with(0, 99)); // → [ 99, 1, 10, 2 ]
console.log(nums); // → [ 3, 1, 10, 2 ]
| 破壊的 | 非破壊(ES2023) | 以前の書き方 |
|---|---|---|
arr.sort(f) |
arr.toSorted(f) |
[...arr].sort(f) |
arr.reverse() |
arr.toReversed() |
[...arr].reverse() |
arr[i] = x |
arr.with(i, x) |
arr.map((v, j) => (j === i ? x : v)) |
with は範囲外の位置を指定すると RangeError: Invalid index : 5 のようなエラーになります(arr[i] = x は配列を伸ばします)。
並べ替え:sortの数値比較と日本語の順番
sort() を引数なしで呼ぶと、要素を文字列にして辞書順で並べます。
console.log([3, 1, 10, 2].sort()); // → [ 1, 10, 2, 3 ]
console.log([3, 1, 10, 2].sort((x, y) => x - y)); // → [ 1, 2, 3, 10 ]
const fruits = ["いちご", "りんご", "バナナ", "あんず"];
console.log(fruits.toSorted()); // → [ 'あんず', 'いちご', 'りんご', 'バナナ' ]
console.log(fruits.toSorted((x, y) => x.localeCompare(y, "ja"))); // → [ 'あんず', 'いちご', 'バナナ', 'りんご' ]
数値は (a, b) => a - b(降順は b - a)、日本語は localeCompare(b, "ja") を渡します。 引数なしの sort は文字コード順なので、カタカナの「バナナ」がひらがなの後ろに来ます。複数キーは a.done - b.done || a.id - b.id のように || でつなぎます。
検索:find・findLast・at・indexOf
以降の例では、次のタスク一覧を使います。
const tasks = [
{ id: 1, title: "備品を発注", done: true, owner: "佐藤" },
{ id: 2, title: "会議室を予約", done: false, owner: "鈴木" },
{ id: 3, title: "在庫を確認", done: true, owner: "鈴木" },
{ id: 4, title: "記事を公開", done: false, owner: "佐藤" },
];
console.log(tasks.find((t) => t.done).id, tasks.findIndex((t) => t.done)); // → 1 0
console.log(tasks.findLast((t) => t.done).id, tasks.findLastIndex((t) => t.done)); // → 3 2
console.log(tasks.find((t) => t.id === 9), tasks.findIndex((t) => t.id === 9)); // → undefined -1
console.log([1, 2, 3].at(-1), [1, 2, 3][-1]); // → 3 undefined
findLast は後ろから探して最初に見つかった要素を返します(ES2023)。 「最新の完了タスク」のように末尾側が新しいデータで便利です。arr[-1] は末尾ではなく undefined なので、末尾は at(-1) で取り出します。見つからないときは find が undefined、findIndex / indexOf が -1 なので、if (idx !== -1) のように判定します。
判定:includesとindexOfのNaNの違い・some・every
const x = [1, NaN, 3];
console.log(x.includes(NaN), x.indexOf(NaN), x.findIndex(Number.isNaN)); // → true -1 1
console.log([0].includes(-0), [, 1].includes(undefined), [, 1].indexOf(undefined)); // → true true -1
console.log(tasks.some((t) => t.done), tasks.every((t) => t.done)); // → true false
console.log([].every(() => false)); // → true
console.log(Array.isArray([]), Array.isArray({ length: 0 })); // → true false
includes は NaN を見つけられますが、indexOf は -1 を返します。 indexOf は === で比べ、NaN === NaN が false になるためです。空きのある配列([, 1])でも同様の差が出ます。「含むか」だけなら includes、位置が必要なら indexOf(NaNを探すなら findIndex(Number.isNaN))と使い分けます。また、空の配列の every は常に true なので、「全部完了」を判定するときは tasks.length > 0 && tasks.every(...) とします。
変換:map・filter・flat・flatMap
map・filter・reduce の詳しい使い方と落とし穴は「JavaScript map filter reduce 使い方」の記事にまとめているので、ここでは要点と flat 系を扱います。
console.log(tasks.filter((t) => !t.done).map((t) => t.id)); // → [ 2, 4 ]
console.log([[1, 2], [3, [4, [5]]]].flat()); // → [ 1, 2, 3, [ 4, [ 5 ] ] ]
console.log([[1, 2], [3, [4, [5]]]].flat(Infinity)); // → [ 1, 2, 3, 4, 5 ]
console.log(["a b", "c"].flatMap((s) => s.split(" "))); // → [ 'a', 'b', 'c' ]
console.log([1, 2, 3].flatMap((n) => (n % 2 ? [n, n] : []))); // → [ 1, 1, 3, 3 ]
flat() の既定の深さは1段で、すべて平らにするなら flat(Infinity) です。flatMap は「map してから1段 flat」なので、空配列を返せば要素を消し、2要素の配列を返せば増やせます。filterとmapを1回で書けるのが利点です。
結合・分割:concat・スプレッド・slice・join
console.log([1, 2].concat([3], 4)); // → [ 1, 2, 3, 4 ]
console.log([...[1, 2], ...[3]]); // → [ 1, 2, 3 ]
console.log(["a", "b"].join("-"), "a,b".split(",")); // → a-b [ 'a', 'b' ]
console.log([1, 2, 3, 4, 5].slice(1, 3), [1, 2, 3, 4, 5].slice(-2)); // → [ 2, 3 ] [ 4, 5 ]
slice(開始, 終了) は終了位置を含みません。 負の数は末尾からの位置です。名前が似ている splice は元の配列を変えるので、切り出すだけなら slice を使います。
集計:reduce・Object.groupBy・Map.groupBy
console.log([1, 2, 3].reduce((s, n) => s + n, 0)); // → 6
console.log(Math.max(...[3, 9, 2]), Math.min(...[3, 9, 2])); // → 9 2
const byOwner = Object.groupBy(tasks, (t) => t.owner);
console.log(Object.fromEntries(
Object.entries(byOwner).map(([k, v]) => [k, v.map((t) => t.id)])
)); // → { '佐藤': [ 1, 4 ], '鈴木': [ 2, 3 ] }
console.log(Object.getPrototypeOf(byOwner)); // → null
const byDone = Map.groupBy(tasks, (t) => t.done);
console.log(byDone.get(true).map((t) => t.id), byDone.get(false).map((t) => t.id)); // → [ 1, 3 ] [ 2, 4 ]
Object.groupBy(ES2024)は、関数の戻り値をキーにして要素をまとめます。 結果はプロトタイプを持たないオブジェクト(null プロトタイプ)なので、byOwner.hasOwnProperty(...) は使えず、Object.hasOwn(byOwner, "佐藤") や in を使います。キーが真偽値やオブジェクトのときは Map.groupBy を使うと、キーの型がそのまま保たれます(Object.groupBy だとキーは文字列の "true" になります)。
Math.max(...arr) は要素数が多いとエラーになります。 Node.js 22で100万件を渡すと RangeError: Maximum call stack size exceeded でした。大きな配列は reduce((m, n) => Math.max(m, n), -Infinity) を使います。なお、小数の誤差を抑えて合計する Math.sumPrecise がES2026で標準化されましたが、Node.js 22では typeof Math.sumPrecise が "undefined" でした。
重複を除く:SetとMap
console.log([...new Set([3, 1, 3, 2, 1])]); // → [ 3, 1, 2 ]
console.log([...new Map(tasks.map((t) => [t.owner, t])).values()].map((t) => t.id)); // → [ 4, 3 ]
値の重複は [...new Set(arr)] で、最初に出た順を保って除けます。 オブジェクトを特定のキーで重複除去するときは Map に入れます。この書き方は同じキーの後の要素で上書きされるため、担当者ごとの最後のタスク(id 4と3)が残ります。
コピー:スプレッドとstructuredCloneの浅い・深いの違い
const src = [{ n: 1 }, [2]];
const s1 = [...src];
const s2 = src.slice();
const s3 = structuredClone(src);
src[0].n = 99;
console.log(s1[0].n, s2[0].n, s3[0].n); // → 99 99 1
console.log(s1 === src, s1[0] === src[0]); // → false true
try {
structuredClone([() => 1]);
} catch (e) {
console.log(`${e.name}: ${e.message}`); // → DataCloneError: () => 1 could not be cloned.
}
スプレッド [...arr]・slice()・Array.from() は「浅いコピー」で、配列そのものは別でも中のオブジェクトは共有されます。 そのため src[0].n を変えると s1・s2 にも反映されました。中身まで別にしたいなら structuredClone(深いコピー)を使います。ただし関数やDOM要素はコピーできず DataCloneError になります。
JSON.parse(JSON.stringify(arr)) も深いコピーになりますが、Dateが文字列になり undefined や関数は消えるため、structuredClone(Date・Map・Setを保てる)が扱いやすいです。
非同期の値を配列にする:Array.fromAsync(ES2026)
const sleep = (ms, v) => new Promise((r) => setTimeout(() => r(v), ms));
console.log(await Array.fromAsync([sleep(20, "a"), sleep(10, "b")])); // → [ 'a', 'b' ]
async function* gen() { yield 1; yield 2; }
console.log(await Array.fromAsync(gen(), (v) => v * 10)); // → [ 10, 20 ]
Array.fromAsync は、非同期ジェネレーターやPromiseの並びを待ちながら配列にします。 結果は元の順番どおりです。Promise.all と違い要素を1つずつ順番に待つので、同時に実行したい処理には Promise.all を使います。上の例は await をトップレベルで使うため、.mjs ファイルで実行しています。
よくあるつまずきと直し方
| 症状 | 原因 | 直し方 |
|---|---|---|
| 並べ替えたら元の配列も変わった | sort / reverse は破壊的 |
toSorted / toReversed |
const n = arr.push(x) が数値 |
push の戻り値は長さ |
[...arr, x] |
| コピーを変えたら元も変わった | 浅いコピー | structuredClone |
空配列で every が true |
仕様(条件に反する要素がない) | length > 0 && を足す |
forEach の中の await が待たない |
forEach はPromiseを待たない |
for...of か Promise.all(arr.map(...)) |
toSorted is not a function |
古い実行環境(Node.js 18以前など) | Node.js 20以降にする、または [...arr].sort() |
よくある質問
Q. 破壊的メソッドと非破壊メソッドはどう見分けますか?
A. 破壊的なのは push pop shift unshift splice sort reverse fill copyWithin の9つです。 それ以外(map・filter・slice・concat・to〜 系・with など)は元の配列を変えません。
Q. toSorted や Object.groupBy はどの環境で使えますか?
A. Node.js 22と現行の主要ブラウザで使えます。 本記事の例はNode.js v22.22.2ですべて動作を確認しました。古いブラウザにも対応する必要がある場合は、TypeScriptの lib 設定やトランスパイル・ポリフィルの対象を確認します。
Q. 配列の中に値があるかを調べるには includes と some のどちらを使いますか?
A. 値そのものを探すなら includes、条件で探すなら some です。 tasks.includes(obj) は同じオブジェクト(参照)しか見つけないので、オブジェクトの配列では tasks.some((t) => t.id === 3) と書きます。
まとめ
- 破壊的メソッドは9つ。それ以外は新しい配列や値を返す
- ES2023の
toSorted・toReversed・toSpliced・withで、元を変えずに並べ替え・置き換えができる sort()は文字列比較。数値は(a, b) => a - b、日本語はlocaleCompare(b, "ja")- 末尾は
at(-1)、後ろから探すならfindLast、NaNを探すならincludes - グループ分けは
Object.groupBy(キーが文字列)とMap.groupBy(キーの型を保つ) - スプレッドは浅いコピー、
structuredCloneは深いコピー - 非同期の値の配列化は
Array.fromAsync、同時実行はPromise.all
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「JavaScript 配列 操作 一覧|全メソッド早見表とNode 22実行結果」
株式会社RJCでは、言語の新しい機能を実際に動かして確かめ、その結果をプロジェクトの中で仲間と共有しています。こうした知識を共有しながら、日々技術を磨いています。
株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。
WE ARE HIRING
RJCで一緒に開発しながら、
成長を楽しみませんか?
RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!
- 127日年間休日
- 12時間平均残業時間
- 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!
ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。