JavaScriptで配列から要素を削除する方法は複数あります。「元の配列を変更するか(破壊的)」「新しい配列を返すか(非破壊的)」の違いを理解して使い分けることが、バグのないコードを書く上で重要です。
この記事では基本的な削除メソッドの比較から、インデックス指定・条件一致・複数一括・オブジェクト配列の削除まで、実践パターンを体系的に解説します。
削除方法の全体比較
| 方法 | 破壊的 | 用途 | 戻り値 |
|---|---|---|---|
splice(i, n) |
◯ | インデックス指定で削除 | 削除した要素の配列 |
filter(fn) |
✕ | 条件に合う要素を除いた新配列 | 新しい配列 |
pop() |
◯ | 末尾の要素を削除 | 削除した要素 |
shift() |
◯ | 先頭の要素を削除 | 削除した要素 |
delete arr[i] |
◯ | ※非推奨。穴が空く | true |
どちらを使うべきか:React の state などイミュータブルに扱いたい場合は
filter を使います。ローカル変数の配列をその場で変更してよい場合は splice / pop / shift が効率的です。splice でインデックスを指定して削除
splice(開始インデックス, 削除数) は元の配列を直接変更し、削除した要素を配列で返します。
splice の基本
const fruits = ['りんご', 'バナナ', 'ぶどう', 'みかん']; // インデックス 1 から 1 件削除 const removed = fruits.splice(1, 1); console.log(fruits); // ['りんご', 'ぶどう', 'みかん'] console.log(removed); // ['バナナ'](削除された要素)
splice で複数削除・末尾からも指定可
const nums = [10, 20, 30, 40, 50]; // インデックス 1 から 2 件削除 nums.splice(1, 2); console.log(nums); // [10, 40, 50] // 負のインデックス(末尾から数える) const colors = ['red', 'green', 'blue', 'yellow']; colors.splice(-2, 1); // 末尾から2番目('blue')を削除 console.log(colors); // ['red', 'green', 'yellow']
値でインデックスを探して削除(indexOf + splice)
値を指定して削除
const fruits = ['りんご', 'バナナ', 'ぶどう', 'みかん'];
function removeFirst(arr, value) {
const index = arr.indexOf(value);
if (index !== -1) arr.splice(index, 1);
return arr;
}
removeFirst(fruits, 'バナナ');
console.log(fruits); // ['りんご', 'ぶどう', 'みかん']
// 存在しない値を渡しても安全(indexOf が -1 を返すとガード)
removeFirst(fruits, 'パイナップル');
console.log(fruits); // ['りんご', 'ぶどう', 'みかん'](変化なし)
delete arr[i] は使わないこと。delete で削除すると要素の値が undefined になるだけで、配列の長さは変わりません(穴あき配列)。splice は要素を完全に取り除いて長さも詰めます。filter で条件に一致する要素を削除(非破壊的)
filter は元の配列を変更せず、条件を満たす要素だけを残した新しい配列を返します。「特定の要素を除いた配列が欲しい」ときに最も適しています。
filter で特定の値を除外
const fruits = ['りんご', 'バナナ', 'ぶどう', 'バナナ', 'みかん']; // 'バナナ' をすべて除去(重複も含めて削除) const result = fruits.filter(f => f !== 'バナナ'); console.log(fruits); // ['りんご', 'バナナ', 'ぶどう', 'バナナ', 'みかん'](元は変わらない) console.log(result); // ['りんご', 'ぶどう', 'みかん']
filter で複数条件・falsy 値の除去
const scores = [85, null, 72, undefined, 0, 95, '', 60]; // null / undefined だけ除去(0 や空文字は残す) const noNulls = scores.filter(x => x != null); console.log(noNulls); // [85, 72, 0, 95, '', 60] // すべての falsy 値を除去(0・空文字・null・undefined) const truthy = scores.filter(Boolean); console.log(truthy); // [85, 72, 95, 60]
filter(Boolean) の注意:0 や ""(空文字列)も falsy として除去されます。0 を残したい場合は filter(x => x != null) を使いましょう。pop・shift で先頭・末尾を削除
先頭・末尾の削除には専用メソッドが使えます。splice より意図が明確になります。
pop(末尾)と shift(先頭)
const queue = ['Alice', 'Bob', 'Carol', 'Dave']; // 先頭を取り出す(キュー処理) const first = queue.shift(); console.log(first); // 'Alice' console.log(queue); // ['Bob', 'Carol', 'Dave'] // 末尾を取り出す(スタック処理) const last = queue.pop(); console.log(last); // 'Dave' console.log(queue); // ['Bob', 'Carol'] // 空配列に対しては undefined を返す(エラーにならない) const empty = []; console.log(empty.pop()); // undefined
| メソッド | 操作 | 計算量 | 備考 |
|---|---|---|---|
pop() |
末尾削除 | O(1) | 高速。スタック(LIFO)実装に使う |
shift() |
先頭削除 | O(n) | 全要素を1つずつ前にずらすため大きい配列は遅い |
大量のキュー処理には
shift() より Map や連結リストの方が効率的です。数百件程度なら問題ありませんが、数万件規模になると shift() の O(n) コストが顕在化します。オブジェクト配列から条件で削除
実務では「ユーザーID が一致する要素を削除」のような、オブジェクト配列の操作が頻繁に登場します。
ID で特定のオブジェクトを削除
const users = [
{ id: 1, name: '田中', active: true },
{ id: 2, name: '鈴木', active: false },
{ id: 3, name: '佐藤', active: true },
{ id: 4, name: '山田', active: false },
];
// id=2 のユーザーを削除(非破壊的)
const withoutUser2 = users.filter(u => u.id !== 2);
console.log(withoutUser2.map(u => u.name)); // ['田中', '佐藤', '山田']
// 非アクティブなユーザーをすべて削除
const activeUsers = users.filter(u => u.active);
console.log(activeUsers.map(u => u.name)); // ['田中', '佐藤']
splice でオブジェクトを破壊的に削除(findIndex を使う)
const tasks = [
{ id: 'a1', title: 'デザイン確認' },
{ id: 'b2', title: 'コードレビュー' },
{ id: 'c3', title: 'テスト実施' },
];
function removeTaskById(arr, id) {
const index = arr.findIndex(t => t.id === id);
if (index !== -1) arr.splice(index, 1);
}
removeTaskById(tasks, 'b2');
console.log(tasks.map(t => t.title));
// ['デザイン確認', 'テスト実施']
複数要素を一括削除するパターン
削除したいインデックスや値が複数ある場合のパターンです。
インデックス配列を指定して削除
// 削除するインデックスを配列で指定
function removeAtIndexes(arr, indexes) {
// 降順にソートしてから splice することでインデックスのずれを防ぐ
const sorted = [...indexes].sort((a, b) => b - a);
sorted.forEach(i => arr.splice(i, 1));
return arr;
}
const nums = [10, 20, 30, 40, 50, 60];
removeAtIndexes(nums, [1, 3, 5]); // インデックス 1・3・5 を削除
console.log(nums); // [10, 30, 50]
Set を使って複数値を一括削除
const removeValues = (arr, ...values) => {
const set = new Set(values);
return arr.filter(x => !set.has(x));
};
const fruits = ['りんご', 'バナナ', 'ぶどう', 'みかん', 'バナナ'];
const result = removeValues(fruits, 'バナナ', 'ぶどう');
console.log(result); // ['りんご', 'みかん']
重複要素の削除(配列の一意化)については配列の重複を簡単に削除する方法(Set・filter の活用)で詳しく解説しています。
先頭・末尾 n 件をまとめて削除
slice を使って先頭・末尾を除いた新しい配列を作る非破壊的パターンです。
先頭・末尾 n 件を除外
const nums = [1, 2, 3, 4, 5, 6, 7, 8]; // 先頭 2 件を除く const withoutFirst2 = nums.slice(2); console.log(withoutFirst2); // [3, 4, 5, 6, 7, 8] // 末尾 3 件を除く const withoutLast3 = nums.slice(0, -3); console.log(withoutLast3); // [1, 2, 3, 4, 5] // 先頭 1 件・末尾 1 件を除く(枠を外す) const trimmed = nums.slice(1, -1); console.log(trimmed); // [2, 3, 4, 5, 6, 7] // 元の配列は変わらない console.log(nums); // [1, 2, 3, 4, 5, 6, 7, 8]
配列を空にする(全削除)
配列を空にする3パターン
let arr = [1, 2, 3, 4, 5]; // ① length を 0 にする(破壊的・高速) arr.length = 0; console.log(arr); // [] // ② splice で全削除(破壊的) arr = [1, 2, 3, 4, 5]; arr.splice(0); console.log(arr); // [] // ③ 空配列を再代入(非破壊的。元の参照は変わらない点に注意) arr = [1, 2, 3, 4, 5]; const ref = arr; // ref は同じ配列を参照 arr = []; // arr は新しい空配列を指す console.log(arr); // [] console.log(ref); // [1, 2, 3, 4, 5] ← ref は古い配列のまま
再代入方式の注意:別の変数が同じ配列を参照している場合、
arr = [] では参照先が変わらず古いデータが残ります。参照を共有しているなら arr.length = 0 または arr.splice(0) を使いましょう。よくある質問(FAQ)
Qsplice と filter どちらを使えばいいですか?
A元の配列を変更してよい場合は splice(速度優先)、元の配列を変えたくない場合(React state など)は filter を使います。filter は重複する値をまとめて削除できる点でも便利です。
Q配列に同じ値が複数ある場合、最初の1件だけ削除するには?
A
indexOf で最初に見つかったインデックスを取得し、splice で1件だけ削除します。filter はすべての一致要素を削除するため、最初の1件だけ消したいときは splice を使います。Qオブジェクト配列から特定のオブジェクトを削除するには?
Aプロパティで条件を指定する方法が2つあります。非破壊なら
filter(u => u.id !== 削除ID)、破壊的なら findIndex でインデックスを探して splice で削除します。オブジェクトの参照比較(arr.indexOf(obj))は同一参照の場合のみ機能します。Qdelete arr[i] ではダメなのですか?
A
delete arr[i] は要素の値を undefined にするだけで配列の長さは変わりません(穴あき配列)。for...in や map で予期しない挙動になるため、配列の要素削除には使わないのが原則です。splice を使ってください。QforEach の中で配列を変更(削除)しても大丈夫ですか?
A危険です。
forEach でループしながら splice で要素を削除すると、インデックスがずれて一部の要素がスキップされます。ループ中に削除が必要な場合は filter で新しい配列を作るか、後ろから前に向かってインデックスを指定して splice する方法が安全です。まとめ
配列の削除方法を用途別にまとめます。
| やりたいこと | 使う方法 |
|---|---|
| インデックス指定で削除(破壊的) | splice(i, n) |
| 値を指定して最初の1件削除 | indexOf + splice |
| 条件に一致するものをすべて削除(非破壊的) | filter(fn) |
| 末尾を削除・取り出す | pop() |
| 先頭を削除・取り出す | shift() |
| 先頭・末尾 n 件を除いた新配列(非破壊) | slice(n) / slice(0, -n) |
| 複数の値を一括削除 | Set + filter |
| 配列を空にする | arr.length = 0 / splice(0) |
配列への要素の追加方法については配列に要素を追加する方法を、条件で要素を抽出する使い方については配列から条件に合う要素を取り出す方法もあわせて参照してください。
