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件
JavaScriptslice は元を壊さないため、状態管理(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]
JavaScriptshift/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"]
JavaScriptslice は“読むだけ”、splice は“書き換え”。副作用が問題になる場面では slice(+スプレッド)を組み合わせて、非破壊で同じ形を作るのが安全です。
非破壊で“挿入した形”を作る(slice+スプレッド)
const a = ["A", "C"];
const i = 1;
const inserted = [...a.slice(0, i), "B", ...a.slice(i)];
// ["A","B","C"]
JavaScriptsplice を使わずに“前後を切って結合”すれば、挿入も非破壊で表現できます。
多次元配列・オブジェクト配列での注意点
浅いコピーなので“内側の参照”は共有される
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 = 0 や a.splice(0) を理解したうえで使い分けてください。浅いコピーで“内側が共有される”ことを見落とすと、入れ子の更新が元にも波及します。多次元やオブジェクト配列では、必要に応じて要素ごとに slice やスプレッドで複製、完全独立なら structuredClone を選びましょう。
まとめ
slice は「指定範囲を非破壊で切り出す」メソッドで、終了は“含まない”半開区間が基本です。負のインデックスで末尾からの相対指定ができ、全体の浅いコピー、先頭・末尾の除去、ページングなどに最適。splice との違いは“非破壊か破壊的か”。状態管理や共有配列では slice(+スプレッド)を使って“前後を切って結合”する発想が安全です。浅いコピーの性質を理解し、入れ子やオブジェクト配列では複製の深さを選べば、初心者でも直感的で壊れにくい部分操作が書けます。
