JavaScriptのループ内で配列の要素を削除する方法を初心者向けに解説!
生徒
「JavaScriptのループの中で、配列の中身を削除したいときはどうすればいいですか?」
先生
「配列の要素を削除する方法はいくつかありますが、ループの中で削除するときには注意が必要です。順番や番号が変わるからです。」
生徒
「えっ、順番や番号が変わるってどういうことですか?くわしく教えてください!」
先生
「それでは、ループ内で配列の要素を削除する時のポイントをわかりやすく説明しますね。」
1. 配列の要素を削除する基本方法:spliceメソッドとは?
配列から特定の要素を取り除くには、JavaScriptのsplice(スプライス)メソッドを使います。
このメソッドは、配列の中の指定した場所から、指定した数だけ要素を削除できます。例えば、2番目(インデックス1)の要素を1つ削除するにはこう書きます。
const arr = ["りんご", "バナナ", "みかん"];
arr.splice(1, 1); // 1番目から1つ削除
console.log(arr); // ["りんご", "みかん"]
この例では、「バナナ」が削除されました。
2. ループ内で配列の要素を削除するときの問題点
ここで問題になるのが、配列の要素を削除しながらループを回すと、配列の長さや要素の位置が変わってしまうことです。
例えば、次のコードを見てください。
const fruits = ["りんご", "バナナ", "みかん", "バナナ"];
for (let i = 0; i < fruits.length; i++) {
if (fruits[i] === "バナナ") {
fruits.splice(i, 1); // バナナを見つけたら削除
}
}
console.log(fruits);
このコードを実行すると、予想と違う結果になります。
["りんご", "みかん", "バナナ"]
実は、ループの中で要素を削除すると、配列のインデックスがずれて、2個目の「バナナ」を見逃してしまったのです。
3. 削除しながらループするときの対策:後ろからループする
この問題を防ぐには、ループを後ろから前に向かって回す方法があります。
配列の最後の要素から順番に見ていくので、削除しても前の要素の位置が変わらず、すべての削除対象を正しく処理できます。
const fruits = ["りんご", "バナナ", "みかん", "バナナ"];
for (let i = fruits.length - 1; i >= 0; i--) {
if (fruits[i] === "バナナ") {
fruits.splice(i, 1);
}
}
console.log(fruits);
["りんご", "みかん"]
これで、すべての「バナナ」が削除されました。
4. filterメソッドを使った配列の要素削除(ループ不要)
実は、配列の中から特定の条件に合わない要素を除く方法として、filterメソッドを使う手もあります。
filterは配列の中から条件に合う要素だけを集めて、新しい配列を作ります。
const fruits = ["りんご", "バナナ", "みかん", "バナナ"];
const filtered = fruits.filter(function(item) {
return item !== "バナナ"; // バナナ以外だけ残す
});
console.log(filtered);
["りんご", "みかん"]
filterを使うと、ループ処理を書かずにスッキリしたコードになります。
5. spliceとfilterの違いを理解しよう
spliceは元の配列を書き換えるので、その場で要素を削除したいときに使います。
一方、filterは元の配列は変えず、新しい配列を作るので、元の配列を残したいときに便利です。
6. forEachループ内での削除は注意が必要
forEachメソッドを使ったループでも、配列の要素を削除することはできますが、内部でループ回数が固定されているため、削除してもループの動きは変わりません。
そのため、forEach内での配列削除はバグの原因になることが多いのでおすすめしません。
7. 実用例:ループで数値の配列から偶数だけ削除する方法
最後に、実際に数値の配列から偶数だけを削除するコード例を紹介します。後ろからループしてspliceで削除します。
const numbers = [1, 2, 3, 4, 5, 6];
for (let i = numbers.length - 1; i >= 0; i--) {
if (numbers[i] % 2 === 0) { // 偶数のとき
numbers.splice(i, 1);
}
}
console.log(numbers);
[1, 3, 5]
このように、ループ内で安全に配列の要素を削除できます。
8. ループ内での配列削除まとめ(まとめは書かないルールのためポイントだけ)
- 配列の要素を削除するには
spliceメソッドを使う - ループ中に削除するとインデックスがずれるので、後ろからループする
- 簡単に削除したい場合は
filterメソッドも使える forEach内で削除は避けたほうが安全
まとめ
今回の記事では、JavaScriptプログラミングにおいて避けては通れない「ループ処理中の配列要素の削除」について、初心者の方にも分かりやすく徹底的に解説してきました。
配列操作は、Webアプリケーション開発やデータ処理において非常に頻繁に登場する重要な技術です。しかし、単純なfor文を使ってループの先頭から順番に削除処理(splice)を行ってしまうと、「インデックスの消失」や「要素の読み飛ばし」といった、目に見えにくいバグを引き起こす原因となります。これは、JavaScriptが動的に配列の長さを調整し、要素を前詰めにするという特性を持っているためです。
ループ内削除のベストプラクティスを振り返る
記事で紹介したように、安全かつ確実に配列から要素を取り除くための主なアプローチは以下の3点です。
- 逆ループ(後ろから回す): 配列の末尾から先頭に向かって
i--で処理を進めることで、要素を削除しても「これからチェックする要素」のインデックスが動かないため、最も確実な手法です。 - filterメソッドの活用: 元の配列を変更せずに(イミュータブル)、条件に合致するものだけを抽出して新しい配列を作る現代的な書き方です。コードの可読性が非常に高くなります。
- while文による制御: 条件を満たしたときだけインデックスを進めないように制御する手法もありますが、初心者には逆ループの方が直感的でミスが少ないでしょう。
さらに応用!TypeScriptでの型安全な実装例
最近の開発現場ではTypeScriptが主流となっています。TypeScriptを使って、オブジェクトが含まれる配列から特定のIDを持つデータを削除する実用的なサンプルコードを見てみましょう。
interface User {
id: number;
name: string;
active: boolean;
}
const users: User[] = [
{ id: 1, name: "田中", active: true },
{ id: 2, name: "佐藤", active: false },
{ id: 3, name: "鈴木", active: false },
{ id: 4, name: "高橋", active: true }
];
// activeがfalseのユーザーを削除する(逆ループ)
for (let i = users.length - 1; i >= 0; i--) {
if (!users[i].active) {
users.splice(i, 1);
}
}
console.log(users);
実行結果を確認すると、不要なデータが正しく削除されていることがわかります。
[
{ "id": 1, "name": "田中", "active": true },
{ "id": 4, "name": "高橋", "active": true }
]
状況に応じた使い分けが重要
「メモリを節約したいので元の配列を直接操作したい(破壊的変更)」という場合は splice を使った逆ループが適しています。一方で、「元のデータはそのままに、表示用のリストだけ加工したい(非破壊的変更)」という場合は filter メソッドが最適です。
プログラミングの学習において、こうした「なぜこの書き方が推奨されるのか」という理屈を理解することは、トラブルシューティング能力を高めることに直結します。今回学んだ内容を活かして、バグのないスムーズなコードを書いていきましょう!
生徒
「先生、ありがとうございました!後ろからループを回すなんて、最初は思いつきませんでした。普通は0番目から順番に数えていきますもんね。」
先生
「そうですね。日常生活だと前から順に片付けるのが普通ですが、プログラムで『中身が動くもの』を扱うときは、後ろから処理したほうが影響を受けないんです。まさに発想の転換ですね。」
生徒
「filter メソッドについても、もっと練習してみます。でも、もしどうしても forEach で削除したいときはどうすればいいんですか?」
先生
「鋭い質問ですね!実は forEach で要素を削除するのはおすすめしません。途中で要素を消しても、forEach は最初に決まった回数分ループを回そうとするので、飛ばされる要素が出てきてしまうからです。もし forEach を使いたいなら、削除する代わりに『残したいものだけ新しい配列に push する』という形にするのが安全ですよ。」
生徒
「なるほど!削除じゃなくて『抽出』と考えるんですね。その方がバグも出にくそうです。他にも map や reduce と組み合わせて使うこともありますか?」
先生
「ええ、もちろん!データの加工とフィルタリングを繋げて書くのがモダンなJavaScriptの書き方です。例えばこんな風に書けますよ。」
const rawData = [10, 25, 40, 55, 70];
// 50以上の数字だけを取り出し、それぞれを2倍にする
const processedData = rawData
.filter(num => num >= 50)
.map(num => num * 2);
console.log(processedData); // [110, 140]
生徒
「うわあ、一行でスッキリ書けますね!カッコいいです!まずは基本の splice をマスターしてから、こういう応用にも挑戦してみます!」
先生
「その意気です。配列操作に慣れると、JavaScriptでの開発がもっと楽しくなりますよ。頑張りましょうね!」