703 字
4 分鐘

JavaScript splice 回傳空陣列?分清刪除結果與原陣列

items.splice(1, 0, item) 已把資料插入陣列,接住的結果卻是 []。splice 會修改原陣列,回傳值則是被刪除元素組成的陣列;刪除數量為零時,空回傳值就是預期結果。 要拿修改後的內容,繼續使用原陣列;要保留原陣列並取得編輯後副本,可選 toSpliced()。

同時檢查回傳值與原陣列#

下面兩個 JavaScript 區塊可分別存成 .mjs,使用 Node.js 執行。MDN splice的第二個參數是刪除數量;slice 的第二個參數則是結束索引,且不包含該位置。

import assert from 'node:assert/strict';
const items = ['A', 'C'];
const removed = items.splice(1, 0, 'B');
assert.deepEqual(removed, []);
assert.deepEqual(items, ['A', 'B', 'C']);
assert.deepEqual(items.splice(1, 1, 'X'), ['B']);
assert.deepEqual(items, ['A', 'X', 'C']);
assert.deepEqual(items.slice(1, 2), ['X']);
assert.deepEqual(items, ['A', 'X', 'C']);
const omitted = ['A', 'B', 'C'];
assert.deepEqual(omitted.splice(1), ['B', 'C']);
const explicit = ['A', 'B', 'C'];
assert.deepEqual(explicit.splice(1, undefined), []);
assert.deepEqual(explicit, ['A', 'B', 'C']);
const original = [{ id: 'A' }, { id: 'B' }];
const edited = original.toSpliced(1, 1);
assert.equal(original.length, 2);
assert.equal(edited.length, 1);
assert.equal(edited[0], original[0]); // 保留元素的物件仍共用參照
console.log('splice return and mutation: PASS');

省略 deleteCount 會從起點刪到最後;明確傳 undefined 則轉成零。因此將可選欄位直接塞進 splice(start, options.deleteCount),和只傳 splice(start) 可能有不同結果。包裝函式應先決定預設語意,再組合參數。

toSpliced回傳編輯後的新陣列,與 splice 的回傳契約不同。它保留的物件元素仍是同一份參照;若接著修改 edited[0].id,原陣列對應物件也會變。需要隔離物件內容時,再評估 structuredClone 的支援型別與限制。

依 ID 刪除前,先接住 findIndex 的 -1#

清單沒有該 ID 時,findIndex 回傳 -1。直接交給 splice(-1, 1) 會刪掉最後一筆,這比空回傳值更容易傷到資料。

這個 helper 限定普通、無空槽且 ID 唯一的資料陣列,回傳新的清單與是否找到。找不到時保留原參照,讓呼叫端明確顯示「資料已不存在」。

import assert from 'node:assert/strict';
function removeFirstById(items, id) {
const index = items.findIndex(item => item.id === id);
if (index === -1) return { found: false, items };
return { found: true, items: items.toSpliced(index, 1) };
}
const original = [{ id: 'A' }, { id: 'B' }, { id: 'C' }];
const missing = removeFirstById(original, 'missing');
assert.equal(missing.found, false);
assert.equal(missing.items, original);
assert.deepEqual(original.map(item => item.id), ['A', 'B', 'C']);
const result = removeFirstById(original, 'B');
assert.equal(result.found, true);
assert.deepEqual(result.items.map(item => item.id), ['A', 'C']);
assert.notEqual(result.items, original);
assert.equal(result.items[0], original[0]);
assert.equal(original.length, 3);
assert.equal(removeFirstById([], 'A').found, false);
console.log('missing ID preserves data: PASS');

函式名稱中的 First 也交代只刪除第一筆符合項目。若資料可能有重複 ID,應先在入口決定重複資料的處理規則,可參考 Set 與依 ID 去重的差異。

2026-11-04 維護流程在 macOS、Node.js v24.13.0 執行上述兩個程式,斷言通過。部署到較舊環境前,先確認 typeof Array.prototype.toSpliced === 'function';缺少時,可在確認 index 非負後,用 items.slice(0, index).concat(items.slice(index + 1)) 組合副本。本文未測試框架的畫面更新機制。

參考資料:

MDN:Array.prototype.splice()

MDN:Array.prototype.toSpliced()

ECMAScript:Array.prototype.splice

JavaScript splice 回傳空陣列?分清刪除結果與原陣列
https://laplusda.com/posts/javascript-splice-return-value-delete-by-id/
作者
Zero
發佈於
2026-11-04
許可協議
CC BY-NC-SA 4.0