本文 AI 產出,尚未審核

JavaScript 陣列操作:slicesplice 完全指南


簡介

在 JavaScript 中,陣列(Array)是最常使用的資料結構之一,幾乎每個前端或 Node.js 專案都離不開它。掌握陣列的切割與修改技巧,不僅能讓程式碼更簡潔,也能提升效能與可讀性。

Array.prototype.sliceArray.prototype.splice 是兩個外觀相似、卻功能截然不同的 API。slice 用於 非破壞性(non‑mutating)的取子陣列,而 splice 則是 破壞性(mutating)的增刪改工具。對於新手而言,常因兩者的參數與回傳值混淆而踩到坑;對於中階開發者,則需要了解它們在大型資料處理、immutable 程式設計等情境下的最佳使用方式。

本篇文章將從概念說明、實作範例、常見陷阱到實務應用,完整闡述 slicesplice,幫助你在日常開發中得心應手。


核心概念

1. slice:取出子陣列(不改變原始陣列)

參數 說明
begin (可選) 起始索引(包含),支援負值,負值表示從陣列尾端倒數。預設值為 0
end (可選) 結束索引(不包含),同樣支援負值。若省略,則切到陣列最後。

回傳值新陣列,原陣列保持不變。

範例 1:基本用法

const fruits = ['🍎', '🍊', '🍇', '🍉', '🥭'];

// 取出第 1~3 個元素(含第 1,不含第 3) -> ['🍊', '🍇']
const part = fruits.slice(1, 3);
console.log(part);      // ['🍊', '🍇']
console.log(fruits);    // 原陣列未變

範例 2:使用負索引

// 從倒數第 2 個開始取到最後 -> ['🥭']
const lastTwo = fruits.slice(-2);
console.log(lastTwo);   // ['🍉', '🥭']

範例 3:淺拷貝(shallow copy)

// 直接不傳參數,可得到原陣列的淺拷貝
const copy = fruits.slice();
copy[0] = '🍌';
console.log(copy);      // ['🍌', '🍊', '🍇', '🍉', '🥭']
console.log(fruits);    // 仍是原本的 ['🍎', '🍊', '🍇', '🍉', '🥭']

slice 只做「淺層」拷貝,若陣列裡的元素本身是物件或其他陣列,拷貝後仍指向同一個參考。


2. splice:在原位增刪改(會改變原始陣列)

參數 說明
start 起始索引(必填),負值同樣表示從尾端倒數。
deleteCount (可選) 要刪除的元素數量,若為 0 表示不刪除。若省略,則刪除從 start 起到陣列結尾的所有元素。
item1, item2, ... (可選) 要插入的新元素,可傳入任意數量。

回傳值被刪除的元素組成的陣列(若未刪除則回傳空陣列),而原陣列則被 直接修改

範例 4:刪除元素

let colors = ['red', 'green', 'blue', 'yellow'];

// 從索引 1 開始,刪除 2 個元素 -> ['green', 'blue']
const removed = colors.splice(1, 2);
console.log(removed);   // ['green', 'blue']
console.log(colors);    // ['red', 'yellow']

範例 5:插入元素

// 在索引 2 的位置插入兩個元素,且不刪除任何東西
colors.splice(2, 0, 'orange', 'purple');
console.log(colors);    // ['red', 'yellow', 'orange', 'purple']

範例 6:同時刪除與插入(取代)

// 將索引 1 的元素取代成 'cyan' 與 'magenta'
colors.splice(1, 1, 'cyan', 'magenta');
console.log(colors);    // ['red', 'cyan', 'magenta', 'orange', 'purple']

範例 7:刪除至結尾

// 從索引 3 開始,刪除到結尾
const tail = colors.splice(3);
console.log(tail);      // ['orange', 'purple']
console.log(colors);    // ['red', 'cyan', 'magenta']

常見陷阱與最佳實踐

陷阱 說明 解決方式
誤以為 slice 會改變原陣列 初學者常把 slice 當成「切掉」的動作,結果發現原陣列沒變。 記住 「slice = 取子,不改變」;若真的要改變,改用 spliceArray.prototype.copyWithin
splice 的返回值被忽略 splice 回傳被刪除的項目,若忘記接收,會失去重要資訊。 將返回值存起來(如 const removed = arr.splice(...);),或直接在需要時使用。
負索引的行為差異 slice(-1) 取最後一個元素,splice(-1, 1) 則會 刪除 最後一個元素。 先在小範例測試負索引行為,避免意外刪除。
一次刪除太多導致資料遺失 splice(start) 若忘記 deleteCount,會一次刪除至結尾。 明確寫出 deleteCount,或使用 slice 先取子陣列再自行處理。
淺層拷貝的副作用 slicesplice 都是淺層操作,對於嵌套物件仍是同一個參考。 若需要深層拷貝,可使用 JSON.parse(JSON.stringify(arr))structuredClone(Node 17+)。

最佳實踐

  1. 盡量保持資料不可變(immutable)
    在 React、Vue 等框架中,slice 常用於產生新陣列以觸發 UI 更新;避免直接使用 splice,除非確定不會破壞 state。

  2. 使用解構賦值搭配 slice

    const [first, ...rest] = array.slice(1);
    

    這樣寫更具可讀性,且不會改變原陣列。

  3. 一次性完成多步驟操作
    若需要「刪除 + 插入」的取代功能,直接使用 splice 而非先 slicepush,可減少遍歷次數,提高效能。

  4. 避免在大型陣列上頻繁 splice
    splice 會造成後續元素的搬移,時間複雜度為 O(n)。對於大規模資料,考慮 Linked ListMap 結構,或使用 immutable.js 等專門的資料結構庫。


實際應用場景

1. 分頁資料顯示

在前端分頁時,常需要根據目前頁碼取出對應的子集合:

function paginate(arr, page = 1, pageSize = 10) {
  const start = (page - 1) * pageSize;
  return arr.slice(start, start + pageSize);
}

// 範例
const data = Array.from({ length: 95 }, (_, i) => i + 1); // [1,2,...,95]
console.log(paginate(data, 3, 20)); // 第 3 頁,每頁 20 筆 -> [41~60]

2. 從清單中移除已完成的任務

在待辦清單(Todo List)應用中,點擊「完成」按鈕時,需要把該項目從陣列中移除:

function removeTask(tasks, id) {
  const index = tasks.findIndex(t => t.id === id);
  if (index !== -1) {
    // 直接修改原陣列(若使用 Redux,應改為不變性寫法)
    tasks.splice(index, 1);
  }
  return tasks;
}

// 使用
let todos = [{id:1, txt:'買牛奶'}, {id:2, txt:'寫程式'}];
removeTask(todos, 1);
console.log(todos); // [{id:2, txt:'寫程式'}]

3. 文字編輯器的「插入」功能

在簡易的文字編輯器裡,我們可能要在字串陣列的特定位置插入新字元:

function insertChars(arr, pos, ...chars) {
  arr.splice(pos, 0, ...chars);
  return arr;
}

let chars = ['H', 'e', 'l', 'o'];
insertChars(chars, 3, 'l'); // 在索引 3 前插入 'l'
console.log(chars.join('')); // "Hello"

4. 產生「前/後」子集合(Immutable 風格)

在 React 中,我們常會需要保留舊的陣列,同時產生新陣列:

// 取得前 3 個元素,並在最後插入新項目
const newList = [...oldList.slice(0, 3), newItem];

總結

  • slice 不會改變原陣列,適合取子集合、製作淺拷貝或實作 immutable 流程。
  • splice 會直接修改原陣列,是一次完成 刪除、插入、取代 的利器,但使用時要留意副作用。
  • 了解兩者的參數規則(特別是負索引)與回傳值,可避免常見的「資料遺失」或「意外變更」問題。
  • 在實務開發中,依需求選擇正確的 API:UI 更新 多用 slice資料庫同步一次性變更 則可考慮 splice
  • 最後,保持 可讀性效能資料不可變 的原則,才能寫出既簡潔又可靠的程式碼。

祝你在 JavaScript 陣列操作的道路上,玩得開心、寫得順手! 🎉