JavaScript | 配列・オブジェクト:配列の追加・削除 – スプレッド構文での追加

JavaScript JavaScript
スポンサーリンク

スプレッド構文とは何か

スプレッド構文 ... は「配列の“中身”をその場で展開する」書き方です。たとえば [...[1,2]][1,2] と同じ意味になり、[0, ...[1,2], 3][0,1,2,3] を作ります。ここが重要です:スプレッドは“非破壊”で新しい配列を返します。元の配列は変えず、追加・結合・挿入を安全に表現できます。


末尾・先頭への追加(push/unshift の非破壊版)

末尾に1件追加

const a = [1, 2];
const next = [...a, 3];
console.log(next); // [1, 2, 3]
console.log(a);    // [1, 2](元は不変)
JavaScript

ここが重要です:push は元を壊しますが、スプレッドは“新配列”。状態管理(React/Vue など)で差分検知が素直に働きます。

先頭に1件追加

const a = [2, 3];
const next = [1, ...a];
console.log(next); // [1, 2, 3]
JavaScript

ここが重要です:unshift と違って非破壊。先頭操作の高コストを避けたいときも、表示側の並べ替えと併用しやすいです。

複数件を一度に追加

const a = [3, 4];
const next = [1, 2, ...a, 5, 6];
console.log(next); // [1, 2, 3, 4, 5, 6]
JavaScript

ここが重要です:値と配列の中身を“混ぜて”好きな位置に並べられます。ループの push より短く安全に書けます。


途中への挿入(slice と組み合わせる定番パターン)

指定位置に1件挿入

const a = ["A", "C"];
const i = 1; // "C" の前
const next = [...a.slice(0, i), "B", ...a.slice(i)];
console.log(next); // ["A", "B", "C"]
JavaScript

ここが重要です:splice は破壊的。スプレッド+slice なら「前」+「挿入」+「後」を非破壊で合成できます。

複数件をまとめて挿入

const a = [1, 5];
const i = 1;
const items = [2, 3, 4];
const next = [...a.slice(0, i), ...items, ...a.slice(i)];
console.log(next); // [1, 2, 3, 4, 5]
JavaScript

ここが重要です:挿入する配列は“そのまま展開”(...items)。入れ子([items])にならないよう注意。


配列結合(concat の非破壊版として)

複数配列を結合

const a = [1, 2];
const b = [3, 4];
const c = [5];
const merged = [...a, ...b, ...c];
console.log(merged); // [1, 2, 3, 4, 5]
JavaScript

ここが重要です:concat と同じく非破壊。リテラルで「前後に値を挟む」など柔軟に書け、読みやすさが高い場面が多いです。

入れ子にしないためのコツ

const a = [1, 2];
const b = [3, 4];
const wrong = [a, b];        // [[1,2],[3,4]](入れ子)
const right = [...a, ...b];  // [1,2,3,4]
JavaScript

ここが重要です:“中身を入れたい”なら必ず ... で展開。配列をそのまま置くと「配列の配列」になります。


オブジェクト要素・多次元での注意(浅いコピー)

浅いコピーであることを理解する

const users = [{ id: 1 }, { id: 2 }];
const next = [...users];     // 配列の“枠”だけ新しくなる
next[0].id = 999;
console.log(users[0].id); // 999(要素オブジェクトは共有)
JavaScript

ここが重要です:スプレッドは“浅い”。入れ子の配列やオブジェクトは参照が共有されます。要素まで独立させたいなら、要素にもスプレッドを使う、または structuredClone を使います。

const users = [{ id: 1, name: "A" }, { id: 2, name: "B" }];
const next = users.map(u => ({ ...u })); // 要素オブジェクトも複製
JavaScript

多次元配列のコピー

const grid = [[1,2],[3,4]];
const shallow = [...grid];                // 行の参照は共有
const deep = structuredClone(grid);       // 完全独立(対応環境で)
JavaScript

ここが重要です:多次元は「層ごとにスプレッド/slice」、完全分離が必要なら深いコピーを選びます。


実践パターン(状態更新・差し込み・並び替え)

非破壊の追加・削除・置換

const arr = [10, 20, 30];

// 末尾追加
const add = [...arr, 40];

// 先頭削除(shift の非破壊版)
const removeHead = arr.slice(1);

// 位置置換(i の要素を x に)
const i = 1, x = 999;
const replace = [...arr.slice(0, i), x, ...arr.slice(i + 1)];
JavaScript

ここが重要です:UIの差分検知や参照共有を前提にするなら“非破壊”が基本。スプレッド+slice の型は覚えてしまいましょう。

並び替えを安全に適用

const arr = [3, 1, 2];
const sorted = [...arr].sort((a, b) => a - b); // コピーしてから sort
JavaScript

ここが重要です:sort は破壊的。まずスプレッドでコピーしてから適用すると、元配列を守れます。


パフォーマンスと読みやすさ(選び方の指針)

いつスプレッドを選ぶか

  • 非破壊が欲しいとき: 共有状態・UI再描画の文脈では必須。
  • “その場で形を作る”とき: 前後に値を挟む、途中にまとめて差し込むなど、リテラルで意図を見せたい場面。
  • 短く読みやすくしたいとき: ループの push より表明的で、誤操作が減ります。

いつ他手段を選ぶか

  • 巨大配列で頻繁な合成: 何度も新配列を作るとコスト増。必要なら一度で合成する、あるいはアルゴリズム側を見直す。
  • 要素の深い独立が必要: スプレッドは浅い。入れ子の安全性が要件なら structuredClone や要素複製を併用。

まとめ

スプレッド構文は「配列の中身を展開して、新しい配列を非破壊で作る」ための最強の道具です。末尾・先頭追加、途中挿入、結合、置換を、slice と組み合わせて短く安全に書けます。入れ子やオブジェクト要素は“浅い”点に注意し、必要に応じて要素複製や深いコピーを選ぶ。push・unshift・splice の“破壊的操作”を使う前に、「スプレッドなら非破壊で書けるか?」を考える習慣を持てば、初心者でも副作用のない、読みやすい配列更新が安定して書けます。

タイトルとURLをコピーしました