【JavaScript】配列の削除方法を初心者向けにわかりやすく解説
はじめに
JavaScriptで配列の要素を削除したい場面は、実務でも日常的にありますね。
たとえば、Webアプリケーションでユーザーが登録したデータを取り除いたり、ショッピングカートから商品を削除したりするケースです。
これらの機能を実装するには、配列の要素を削除する方法をしっかり理解しておくことが大切でしょう。
しかし、初心者の方にとっては「どんな書き方があるのか?」「実際のコードはどうなるの?」といった疑問が浮かぶのではないでしょうか。
この記事では、そんな疑問を解消するため、いろいろな削除方法を具体的なコード例つきで紹介します。
シチュエーション別の解説や注意点にも触れますので、ぜひ参考にしてみてください。
この記事を読むとわかること
- JavaScriptの配列とは何か、そしてよくある削除ニーズ
- インデックスを指定して要素を削除する代表的な方法
- 条件に合致する要素だけをまとめて削除するにはどうすればいいのか
- 削除時に気をつけたいポイントやパフォーマンスへの考え方
- 具体的な使いどころや実務例との関連
ここから、一つひとつ丁寧に見ていきましょう。
JavaScriptの配列概要
JavaScriptの配列は、単純に値をリスト形式で扱うためによく使われます。
文字列のリストやオブジェクトの一覧などを保持し、必要に応じて値を追加・削除・更新できます。
多くのWebアプリケーションでは、APIから取得したデータを配列として保持し、ユーザーの操作によって削除や更新を行います。
たとえば、カートに追加された商品の一覧を配列で管理し、商品を取り除くときに配列から要素を削除する、といったイメージです。
配列を取り扱うとき、特に削除に関連しては以下のようなポイントが重要になります。
削除方法のバリエーション
単一要素を削除するのか、まとめて削除するのか、あるいは特定の条件に合う要素のみ削除するのかなど、用途によって手法を使い分ける必要があります。
元の配列を変化させるかどうか
JavaScriptでは、配列に対して破壊的メソッド(元の配列を直接変更するメソッド)と非破壊的メソッド(元の配列を変更せず、新しい配列を作るメソッド)があります。
実務では、元の配列を保存しておきたいケースや、逆に直接書き換えたいケースなどさまざまです。
パフォーマンス面の考慮
配列サイズが大きい場合に削除が頻繁に起こると、アプリケーションの動作に影響を及ぼすことがあります。
ただし、初心者の段階ではまず正しく動くコードを書き、のちに最適化を検討するのが一般的です。
こういった基礎知識を押さえながら、具体的な削除方法を見ていきましょう。
要素の削除を行う主な場面
実際の業務や趣味の開発で、どのようなときに配列の削除が必要になるのでしょうか。
想定できる場面をいくつか挙げてみます。
アプリ開発では、ユーザーの操作に応じて動的にリストの内容を更新するケースがとても多いです。
たとえば、以下のようなシーンがあるでしょう。
1. ショッピングカートから商品の削除
ユーザーが「削除」ボタンを押すと、カートの配列からその商品を取り除く必要があります。
2. ToDoリストで完了したタスクを消去
タスク管理アプリで、完了した項目をリストから外すケースが典型的です。
3. ユーザー管理システムで無効なユーザーをリストから外す
非アクティブなアカウントを一覧に表示しないようにするなど、条件を満たさない要素を削除します。
4. 入力フォームで追加されたオプションの削除
ユーザーが動的に項目を追加できる入力フォームで、誤って追加した項目を消せるようにしたい場面があります。
これらは実務でもよくある操作です。
いずれのケースでも、JavaScriptの配列から特定の要素を削除するロジックが不可欠になります。
そのため、さまざまな削除方法を知っておくと応用がききます。
配列の要素削除に役立つ基本メソッド
spliceを使う方法
JavaScriptで配列要素を削除するときに、もっとも有名なメソッドが splice
でしょう。
これはもともと、「指定した範囲の要素を置換・削除・挿入する」ためのメソッドです。
// 例:配列の2番目(インデックス1)から1つの要素を削除 const fruits = ["apple", "banana", "cherry", "date"]; // インデックス1の"banana"を削除 fruits.splice(1, 1); console.log(fruits); // => ["apple", "cherry", "date"]
splice
は第一引数に開始位置、第二引数に削除する要素数を指定します。
上の例ではインデックス1から1つ削除しているため、"banana"が取り除かれました。
ここで注意したいのが、 splice
は破壊的メソッドということです。
つまり、この操作によって fruits
自体が変更されます。
もとの配列を残しておきたい場合は、バックアップを取るか、非破壊的メソッドを活用するなどの工夫が必要です。
実務での活用シーン
ToDoリストなど、一覧から単一のアイテムを削除したい場合に重宝します。
また、ユーザーが配列の順序を手動で変更する機能を実装するときも、 splice
はよく使われるでしょう。
sliceで実は削除はできない
slice
と名前が似ているため、削除用途にも使えるのではと思う方もいるかもしれません。
しかし、 slice
は新しい配列を作る非破壊的メソッドであり、削除専用ではありません。
指定した範囲を抜き出すことはできますが、「ある要素だけ取り除く」という使い方には少し不向きです。
// 例:インデックス1以外だけを集めたい、みたいなことは直接できない const animals = ["dog", "cat", "lion", "tiger"]; // catだけを削除したい場合、sliceを使うとちょっと煩雑になります // 例:catのインデックスが1だと知っていて、前半と後半を合体させる const before = animals.slice(0, 1); // ["dog"] const after = animals.slice(2); // ["lion", "tiger"] const newArr = before.concat(after); console.log(newArr); // => ["dog", "lion", "tiger"]
このように、 slice
を使って削除っぽい処理をすることは可能ですが、 splice
のほうが明らかにわかりやすいでしょう。
したがって、「一部の要素を取り除く」という目的なら splice
か別の方法を選ぶのが一般的です。
popとshift
pop
は配列の末尾から、 shift
は配列の先頭から要素を取り除きます。
両方とも破壊的メソッドです。
const numbers = [10, 20, 30, 40]; // 配列の末尾を削除 numbers.pop(); // => 40 が取り除かれる console.log(numbers); // => [10, 20, 30] // 配列の先頭を削除 numbers.shift(); // => 10 が取り除かれる console.log(numbers); // => [20, 30]
単純に先頭か末尾の要素だけを削除したいときには便利でしょう。
たとえば、キューやスタックといったデータ構造を扱うシステムでも役立ちます。
条件を満たす要素を削除する方法
filterで非破壊的に取り除く
特定の条件を満たす要素を配列からまとめて削除したい場合、 filter
がよく利用されます。
filter
は新しい配列を返す非破壊的メソッドなので、元の配列はそのまま保持されます。
const users = [ { id: 1, name: "Alice", isActive: true }, { id: 2, name: "Bob", isActive: false }, { id: 3, name: "Carol", isActive: true }, ]; // isActive が true のユーザーだけを残す const activeUsers = users.filter(user => user.isActive); console.log(activeUsers); // => [{ id: 1, name: "Alice", isActive: true }, { id: 3, name: "Carol", isActive: true }]
このようにフィルタリングを行うことで、「配列から条件を満たさない要素を除外する」ことが可能です。
実務での活用シーン
- ユーザーリストから退会済みアカウントを除外する
- 商品一覧から在庫切れの商品を表示しないようにする
- フィルタリング機能を提供するUIを作成し、その条件に合うデータのみを残す
特に、大量のオブジェクトを扱う場合、 filter
は読みやすく明快です。
元の配列を保持したいシチュエーションでも安心して使えるのが利点でしょう。
spliceと組み合わせる方法
複数の要素があり、それぞれのインデックスを調べてから1つずつ削除する方法も考えられます。
ただし、このやり方はループ中に配列が変わることでインデックスがずれてしまう可能性があるため、注意が必要です。
たとえば、以下のようなコードを書いた場合に問題が起こります。
const arr = [1, 2, 3, 4, 5]; // 偶数を削除したい for (let i = 0; i < arr.length; i++) { if (arr[i] % 2 === 0) { arr.splice(i, 1); } } console.log(arr); // => 期待通り [1, 3, 5] が残るかと思いきや、配列の長さやインデックスがループ中に変化 // 実際には想定外の挙動が起こることがある
実際の実行環境によっては問題なく動いてしまうケースもあれば、要素が飛ばされるなど予期せぬ結果になるケースもあります。
そのため、要素をまとめて削除するなら、 filter
を使う方が安全です。
もしどうしても splice
でインデックスを使った削除をしたいときは、ループを逆方向に回すなどの工夫が必要になります。
破壊的メソッドと非破壊的メソッド
ここまで紹介したメソッドのうち、 splice
, pop
, shift
は破壊的メソッド、 filter
は非破壊的メソッドでした。
どのように使い分ければいいのでしょうか。
破壊的メソッド
元の配列の状態が変わっても構わない場合。
たとえば、ショッピングカートの配列を直接更新するようなケースなど。
メモリを節約したり、コード量が短くなるメリットがあります。
非破壊的メソッド
元の配列を残して、新しい配列を作りたい場合。
データをロールバックしたり、変更履歴を後からたどりたい場合に適しています。
また、ReactなどのUIフレームワークと合わせて使うとき、非破壊的な操作のほうが再レンダリングの仕組みと相性が良い場面があります。
実際のプロジェクトでどちらを使うかは、要求や設計に応じて判断するといいでしょう。
最終的にはチームのコード方針や可読性の観点で決める場合もあります。
特定の値を持つ要素を削除するには
indexOf + splice
ある値が配列の中で最初に登場するインデックスを取得したうえで、 splice
で削除する方法です。
以下の例では、文字列 "banana"
を見つけて削除します。
const fruits = ["apple", "banana", "cherry", "banana"]; const target = "banana"; const index = fruits.indexOf(target); if (index !== -1) { fruits.splice(index, 1); } console.log(fruits); // => ["apple", "cherry", "banana"] // 最初に見つかった "banana" だけが削除される
この方法は、特定の要素が存在しなければ -1
が返ってくるため、存在チェックを行ってから splice
を使う必要があります。
また、同じ要素が複数含まれる場合は最初に見つかったものだけを削除する点にも注意です。
すべて削除したい場合はループや filter
を使う方法が便利です。
filterを使って特定の値をすべて削除
先ほどの例の通り、複数回登場する値を一気に削除したい場合は filter
を使うとスッキリ書けます。
const fruits = ["apple", "banana", "cherry", "banana"]; const target = "banana"; // targetと等しくない要素のみを集める => 全"banana"が削除される const newFruits = fruits.filter(item => item !== target); console.log(newFruits); // => ["apple", "cherry"]
このように、特定の文字列や数値をまとめて削除する場面では、filter
の方がわかりやすいかもしれません。
メモリとパフォーマンスの視点
初心者のうちはまず動かすことが大事ですが、実務ではパフォーマンスやメモリ使用量にも目を向ける必要があります。
とくに配列が非常に大きい場合、削除するたびに要素のインデックスを詰めるオペレーションが生じるため、アプリが重くなることがあります。
splice
は、削除された部分の後ろにある要素を前へ詰める処理が走ります。filter
は新しい配列を作るので、配列が大きい場合はメモリ消費が増える可能性があります。
そのため、削除回数が膨大かつ配列サイズが大きい場面では、アルゴリズム自体を見直すことも大事です。
たとえば、連想配列的な構造(オブジェクトやMap)にして、キーを指定して値を削除する形のほうが効率的なケースもあります。
破壊的メソッドを使うときの注意点
チーム開発では、配列が破壊的に変更されることで予期しないバグが発生することもあります。
誰かが splice
や pop
を使って配列を直接変更すると、その配列を共有している別の処理に影響を与えかねません。
具体例
function removeItem(arr, index) { arr.splice(index, 1); } const myArray = [1, 2, 3]; removeItem(myArray, 1); console.log(myArray); // => [1, 3] (元の配列が変わっている)
上記のように、関数が受け取った配列そのものを変更しているため、関数を使った箇所が多いと何がどこで変更されているか把握しづらくなるかもしれません。
複雑なコードにならないよう配慮するか、非破壊的なアプローチに切り替えるのも一つの手段です。
イミュータブル思考のメリット
イミュータブルとは、「オブジェクトの状態を変更しない」考え方です。
Reactなどのフレームワークを使うときにはイミュータブルなデータ操作が推奨されることが多いので、配列操作の基本として意識しておくとよいでしょう。
イミュータブルな削除の例
const arr = [1, 2, 3, 4, 5]; // 2と等しい値を取り除きたい const newArr = arr.filter(num => num !== 2); console.log(arr); // => [1, 2, 3, 4, 5] console.log(newArr); // => [1, 3, 4, 5]
元の配列 arr
は変化せずに、新しい配列 newArr
を得られます。
このように、もとのデータを安全に残したまま削除後の配列を扱えるので、デバッグや変更履歴の追跡がしやすくなる場合があります。
削除の結果、意図せずに空要素(穴)ができるケースに注意
JavaScriptには、要素が完全に存在しない「穴(empty slot)」が生じるケースもあります。
たとえば、配列リテラルを使って [1, , 3]
のように要素を飛ばす書き方をすると、その飛ばした位置は「穴」扱いになります。
ただし、削除方法によってはこうした穴が意図せず生じることはあまりありません。
splice
や pop
のようなメソッドを使った場合は要素が詰められるからです。
一方、オブジェクトのプロパティを消すときと混同して、 delete array[index]
を使うと穴ができてしまいます。
const arr = ["apple", "banana", "cherry"]; delete arr[1]; console.log(arr); // => ["apple", empty, "cherry"]
このように delete
を使うと、要素が「undefined になる」のではなく、配列の長さがそのままで空要素が残ります。
意図しない動作につながる可能性が高いので、要素を削除するときに delete
は基本的に使わないほうがいいでしょう。
そもそもdeleteは推奨されない
delete
はオブジェクトのプロパティを削除するための演算子ですが、配列の要素削除としては望ましくありません。
繰り返しになりますが、配列の長さは変わらずに空要素が発生するため、splice
や filter
を使う場面で代用するのが一般的です。
実務上でも、delete array[index]
が書かれているコードを見かけたら、多くの場合はリファクタリングを検討したほうが良いかもしれません。
まとめて要素を初期化(クリア)したい場合
配列自体の要素をまるごと削除し、空の状態にしたい場合があります。
たとえば、フォームをリセットするときや、一時的なキャッシュをまるごと消したいときなどです。
lengthプロパティを0にする
const arr = [1, 2, 3, 4, 5]; arr.length = 0; console.log(arr); // => []
これで配列の中身がすべて消去されます。
破壊的に変更されるので、他の参照先への影響には注意しましょう。
新しい空配列を再代入する
let arr = [1, 2, 3, 4, 5]; arr = []; console.log(arr); // => []
こちらもシンプルで分かりやすいですね。
ただし、 arr
が元々別の変数やコンポーネントで参照されていた場合は、それらへの影響がまったく異なる形になることを理解しておく必要があります(これはオブジェクト参照の性質によるものです)。
配列操作時にありがちなバグと対処法
1. ループ中に配列を破壊的に変更
途中で要素が詰められるため、インデックスの計算が狂ってしまうことがあります。
-> 逆向きループや非破壊的メソッドの活用で対策可能です。
2. delete
を誤用して穴を作る
空要素が生じて配列全体の挙動に違和感が出る可能性があります。
-> splice
や filter
を使うようにしましょう。
3. 複数箇所から参照されている配列に対して破壊的操作をする
予期しない副作用が発生し、別の処理でエラーになるかもしれません。
-> データの流れを整理し、破壊的操作が本当に必要か検討しましょう。
4. 条件分岐を間違えて意図と逆の要素を削除
初心者の方は filter
の条件式や splice
の第二引数などを間違えることが多いです。
-> 1行ずつコードの意味を確認しながらテストしてみるとよいでしょう。
応用例:複数条件で削除
実務では、単純に「この値だけ削除」ではなく、複数条件を組み合わせた削除が求められることがあります。
たとえば、ユーザーのステータスが「退会済み」で、かつ最後のログインから一定期間経過しているなど、いくつかの条件をANDやORで組み合わせて絞り込みを行います。
const users = [ { name: "Alice", isActive: false, lastLogin: 200 }, { name: "Bob", isActive: false, lastLogin: 500 }, { name: "Carol", isActive: true, lastLogin: 20 }, ]; // 複数の条件を満たすユーザーを取り除きたい場合 // ここでは "isActive === false" かつ "lastLogin > 300" のユーザーを削除 const filteredUsers = users.filter(user => { // この条件を満たすと残す // つまり、削除の条件は"false && 300以上"のとき if (user.isActive === false && user.lastLogin > 300) { return false; } return true; }); console.log(filteredUsers); // => [{ name: "Alice", isActive: false, lastLogin: 200 }, { name: "Carol", isActive: true, lastLogin: 20 }] // Bob が削除対象になっている
このように、削除ロジックが複雑になるほど filter
を使ったほうがコードが読みやすいかもしれません。
もし元の配列を直接変えたいなら、ループでインデックスを管理しつつ splice
を使う手段も考えられます。
ReactやVue.jsなどのフレームワークでの配列削除
JavaScriptのフレームワークを使う場合、配列を削除するときに直接破壊的メソッドを使うと、状態管理の仕組みと食い違いが起こるかもしれません。
たとえば、Reactではステートを直接変更すると再レンダリングがトリガーされず、ビューが更新されない場合があります。
そのため、Reactコンポーネントで useState
を使うときなどは、非破壊的な filter
を用いて新しい配列を作るアプローチがよく採用されます。
Vue.jsでも似たような注意点があるため、フレームワークを扱う際は「何を変更し、どのタイミングで再描画されるのか」という仕組みを意識して配列削除の方法を選ぶとよいでしょう。
実務的視点でのまとめ
- 単一要素を破壊的に削除したい:
splice(index, 1)
がシンプル。 - 先頭や末尾を削除したい:
shift()
やpop()
が便利。 - 特定の条件に合う要素をまとめて削除したい:
filter
で削除条件を反転して残すほうがわかりやすい。 - 元の配列を残したい:
filter
などの非破壊的手法を使う。 - 大量データや頻繁な削除がある: パフォーマンス面で別の構造(たとえばオブジェクトのキー削除など)を検討することも視野に。
配列削除の方法を何にするかは、アプリの設計やチームの方針などによって決まることが多いです。 たとえば「原則イミュータブル操作を推奨」などのルールがあるなら、破壊的メソッドは使わないという方針になることもあるでしょう。
よくあるQ&A
Q1. ループで配列要素を削除するときに気をつけることは?
ループ中に splice
などの破壊的メソッドを使うとインデックスが詰められるため、意図しない要素が削除されることがあります。
対策としては、以下のような方法があります。
- 後ろから前へ向かってループする
- 先に削除対象を配列に集めておいて、あとから一括削除する
filter
などを使い、破壊的でない形にする
Q2. delete演算子で配列要素を消すのはダメなの?
使えないわけではありませんが、要素が「穴」になり配列の長さが変わらず残るため、通常は推奨されません。
実務では splice
や filter
を使うのが基本です。
Q3. 複数の同じ要素をすべて削除したいときは?
同じ文字列や数値が何度も登場する場合、 indexOf
と splice
を組み合わせたループを書くのは手間がかかります。
filter
を使うと一気に削除できるため、多くの場面で便利でしょう。
Q4. なぜReactなどでは破壊的メソッドが好まれないの?
Reactのステート管理では、直接配列を破壊的に変更しても再レンダリングが起こらないことがあるためです。
イミュータブルにステートを更新することで、変更検知が正しく働く仕組みになっています。
実務例:ショッピングカート機能
ここでは実際にショッピングカートを想定した例を見てみましょう。
ユーザーが商品を「削除」ボタンで取り除くとき、配列から要素を削除するコードを考えます。
// 商品の例 // id, name, price などをもつオブジェクト配列 let cart = [ { id: 1, name: "Book", price: 1200 }, { id: 2, name: "Pen", price: 100 }, { id: 3, name: "Notebook", price: 200 }, ]; // 削除ボタンを押されたとき、該当するidをもつ要素をカートから取り除く関数 function removeFromCart(productId) { // 破壊的な例: splice を使う const index = cart.findIndex(item => item.id === productId); if (index !== -1) { cart.splice(index, 1); } } // たとえば「idが2のPenを削除」操作 removeFromCart(2); console.log(cart); // => [{ id: 1, name: "Book", price: 1200 }, { id: 3, name: "Notebook", price: 200 }]
このように findIndex
と splice
を組み合わせるやり方は実用的です。
ただし、元の cart
を変更しているため、もし複数箇所で cart
を参照しているなら影響を把握しておく必要があります。
データ管理が複雑な場合は別の構造を検討する
配列の要素数が膨大で、しかも削除や追加が頻繁に行われるようなケースでは、配列を操作するコストが高くなるかもしれません。
たとえば、在庫数が何万件もあるECシステムで、ユーザーが多い時間帯に大量の削除操作が行われる場面などです。
そういったときは、ハッシュマップ(JavaScriptでいえばオブジェクトやMap)を使った方が検索や削除の効率が良い場合があります。
ただし、あまりに構造が複雑になるとメンテナンス性が下がるので、チームの規模やシステムの要件に合わせて検討するといいでしょう。
発展的な考え方
JavaScriptの配列は多機能で便利ですが、実務ではスケールアップに伴ってさまざまな工夫が必要になります。
たとえば、以下のような手法も覚えておくと役立つかもしれません。
- reduce を使って条件に応じた新しい配列を生成する
- Array.prototype.forEach や for...of で要素をチェックしながら別の配列に追加する
- ライブラリを用いて配列操作をより簡単に書く(ただし学習コストとチームの合意が必要)
複雑な配列操作が増えてきたら、配列そのものではなく適切なデータ構造を利用した方が保守しやすくなるかもしれません。
まとめ
JavaScriptで配列から要素を削除する方法は、実装の目的や状況によってさまざまです。
以下のようにまとめると、全体像が把握しやすいでしょう。
単一要素の削除に便利な splice
インデックスを指定して手軽に要素を除去でき、破壊的に配列を変化させる。
ショッピングカートやToDoリストなど、特定の要素をサクッと消したいときに便利です。
先頭・末尾の削除に特化した pop
と shift
スタックやキューの実装など、先頭と末尾を意図的に操作する場合によく使われる。
複数要素や条件付き削除に強い filter
非破壊的に新しい配列を返すため、Reactなどのフレームワークでも使いやすい。
退会済みユーザーや在庫切れ商品など、条件に合った要素をまとめて排除できる。
delete
は配列要素削除には向かない
要素が空になり、配列の長さが変わらないため、予期しないバグを招くおそれがある。
大量データを扱うときのパフォーマンス
削除が頻繁にある場合は、破壊的・非破壊的どちらもコストがかかりやすい。
必要に応じて別のデータ構造やアルゴリズムを検討するとよい。
初心者の皆さんにとっては、「実際に手を動かしながら書いてみる」ことが理解を深める近道です。
配列削除の操作はWebアプリ開発のどんな場面でも遭遇しやすいため、ぜひこの機会に把握しておいてください。
以上が、JavaScriptで配列の要素を削除するための代表的な方法と、その実務での使いどころに関する解説でした。
ひとつずつ試してみると、より理解が深まるでしょう。