JavaScript | 配列・オブジェクト:配列の追加・削除 – slice

JavaScript JavaScript
スポンサーリンク

slice とは何か

slice は「配列から“指定した範囲”を切り出して、新しい配列を返す」非破壊メソッドです。元の配列は変更されず、開始位置から終了位置の“手前まで”がコピーされます。ここが重要です:slice は“読み取り専用の切り出し”。配列を安全に部分取得したり、非破壊の削除・コピー・ページングに最適です。


基本構文と戻り値

範囲指定のルール(開始、終了、終端は含まない)

const a = ["A", "B", "C", "D", "E"];
console.log(a.slice(1, 4)); // ["B","C","D"](開始=1、終了=4の手前まで)
JavaScript

終了インデックスは“含まれない(半開区間)”のがポイントです。数学でいう [start, end) のイメージで覚えると、境界ミスを防げます。

省略時の挙動と境界越え

const a = [0, 1, 2, 3, 4];

// 終了を省略 → 最後まで
console.log(a.slice(2));    // [2, 3, 4]

// 両方省略 → 全体コピー
console.log(a.slice());     // [0, 1, 2, 3, 4]

// 範囲外は安全に切り詰め
console.log(a.slice(2, 999)); // [2, 3, 4]
JavaScript

終了を省略すると“最後まで”。範囲外指定はエラーにならず、可能な範囲だけが返ります。


負のインデックスと at との違い

負の値で“後ろから数える”

const a = ["A", "B", "C", "D", "E"];
console.log(a.slice(-3));      // ["C","D","E"](最後から3つ)
console.log(a.slice(-4, -1));  // ["B","C","D"](最後から4の位置〜最後の1の手前)
JavaScript

負のインデックスは「末尾からの相対位置」。-1 は“最後の要素の位置”を指し、終了は“手前まで”というルールは同じです。

参照だけなら at、部分取得なら slice

const a = [10, 20, 30];
console.log(a.at(-1));   // 30(参照だけ)
console.log(a.slice(-1)); // [30](配列として部分取得)
JavaScript

“値1つ”が欲しいなら at、“部分配列”が欲しいなら slice を選びます。


非破壊の利点とよくある用途

浅いコピーとして使う(全体・一部)

const src = [1, 2, 3];
const copy = src.slice();           // 全体コピー(浅い)
const head2 = src.slice(0, 2);      // 先頭2件
const tail2 = src.slice(-2);        // 末尾2件
JavaScript

slice は元を壊さないため、状態管理(React/Vue)や共有配列でも安心して使えます。浅いコピーなので“枠”だけが独立し、要素がオブジェクトなら参照は共有される点に注意。

先頭・末尾を“除外した形”を作る(非破壊の削除)

const a = [1, 2, 3, 4];
const withoutFirst = a.slice(1);        // [2, 3, 4]
const withoutLast  = a.slice(0, -1);    // [1, 2, 3]
JavaScript

shift/pop の“削除版”を非破壊で実現できます。副作用を避けたいときの定番です。

ページング・ウィンドウ処理

function page(arr, pageNumber, pageSize) {
  const start = (pageNumber - 1) * pageSize;
  const end   = start + pageSize;
  return arr.slice(start, end);
}
console.log(page([1,2,3,4,5,6], 2, 2)); // [3,4]
JavaScript

半開区間ルールを使うと、ページ境界の計算が素直に書けます。


splice との違い(削除・挿入との比較)

非破壊の slice、破壊的な splice

const a = ["A", "B", "C", "D"];

// slice:部分取得(元はそのまま)
console.log(a.slice(1, 3)); // ["B","C"]
console.log(a);             // ["A","B","C","D"]

// splice:削除(元が変わる)
a.splice(1, 2);             // 1番目から2件削除
console.log(a);             // ["A","D"]
JavaScript

slice は“読むだけ”、splice は“書き換え”。副作用が問題になる場面では slice(+スプレッド)を組み合わせて、非破壊で同じ形を作るのが安全です。

非破壊で“挿入した形”を作る(slice+スプレッド)

const a = ["A", "C"];
const i = 1;
const inserted = [...a.slice(0, i), "B", ...a.slice(i)];
// ["A","B","C"]
JavaScript

splice を使わずに“前後を切って結合”すれば、挿入も非破壊で表現できます。


多次元配列・オブジェクト配列での注意点

浅いコピーなので“内側の参照”は共有される

const grid = [[1,2],[3,4]];
const copy = grid.slice();  // 外側の枠だけ新規
copy[0][0] = 999;
console.log(grid[0][0]); // 999(内側配列は共有)
JavaScript

入れ子まで独立させたいなら、行ごとに row.slice() を使う、または structuredClone(grid) で深いコピーを取ります。

オブジェクト配列の更新は map+スプレッドが安全

const users = [{id:1,name:"A"}, {id:2,name:"B"}];
const updated = users.map(u => u.id === 2 ? { ...u, name: "B2" } : u);
JavaScript

要素オブジェクトも複製してから書き換えることで、参照の共有による副作用を避けられます。


よくある落とし穴と回避策

“終了は含まない”を忘れて off-by-one(±1ズレ)を起こしがちです。常に [start, end) と考え、最後を含めたいときは end を“1つ先”にします。配列を空にしたい場合、a.slice(0, 0) は単に空配列を返すだけで元は変わりません。元を縮めたいなら a.length = 0a.splice(0) を理解したうえで使い分けてください。浅いコピーで“内側が共有される”ことを見落とすと、入れ子の更新が元にも波及します。多次元やオブジェクト配列では、必要に応じて要素ごとに slice やスプレッドで複製、完全独立なら structuredClone を選びましょう。


まとめ

slice は「指定範囲を非破壊で切り出す」メソッドで、終了は“含まない”半開区間が基本です。負のインデックスで末尾からの相対指定ができ、全体の浅いコピー、先頭・末尾の除去、ページングなどに最適。splice との違いは“非破壊か破壊的か”。状態管理や共有配列では slice(+スプレッド)を使って“前後を切って結合”する発想が安全です。浅いコピーの性質を理解し、入れ子やオブジェクト配列では複製の深さを選べば、初心者でも直感的で壊れにくい部分操作が書けます。

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