Array.prototype.splice()
splice(start[, deleteCount[, item1, item2, ...]]) The splice() method changes an array by removing, replacing, or adding elements in place. It modifies the original array and returns an array containing the deleted elements (or an empty array if nothing was removed).
Syntax
array.splice(start)
array.splice(start, deleteCount)
array.splice(start, deleteCount, item1)
array.splice(start, deleteCount, item1, item2, /* ... */)
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
start | number | — | Index where to start changing the array. Negative counts from the end. |
deleteCount | number | Infinity | Number of elements to remove. If omitted, removes all elements from start to the end. |
item1, item2, ... | any | — | Elements to add to the array at the start position. |
Examples
Removing elements
const fruits = ['apple', 'banana', 'cherry', 'date'];
const removed = fruits.splice(1, 2);
console.log(fruits);
// ['apple', 'date']
console.log(removed);
// ['banana', 'cherry']
When deleteCount is greater than 0, splice() removes that many elements starting at start and returns them as a new array. The original array shrinks by the number of elements removed. Setting deleteCount to 0 skips removal entirely, which lets you insert elements without deleting anything — the insertion point shifts existing elements to the right.
Adding elements
const colors = ['red', 'blue'];
colors.splice(1, 0, 'green', 'yellow');
console.log(colors);
// ['red', 'green', 'yellow', 'blue']
Setting deleteCount to 0 and providing items inserts those items at the start position without removing anything. The existing elements shift right to make room. This is the cleanest way to insert at an arbitrary index without losing data — no temporary variables or manual shifting needed.
Replacing elements
const numbers = [1, 2, 3, 4, 5];
const removed = numbers.splice(2, 2, 30, 40);
console.log(numbers);
// [1, 2, 30, 40, 5]
console.log(removed);
// [3, 4]
When both deleteCount and replacement items are provided, splice() performs a swap — the removed elements come out and the new ones go in at the same position. The array length changes by the difference between items added and elements removed. This three-in-one behaviour (remove, insert, return removed) makes splice() the Swiss Army knife of array mutation.
Using negative index
const items = ['a', 'b', 'c', 'd', 'e'];
items.splice(-2, 1, 'X');
console.log(items);
// ['a', 'b', 'c', 'X', 'e']
A negative start index counts backward from the end of the array: -2 means the second-to-last element. This is handy when you want to modify the end of an array without knowing its length ahead of time. The negative-offset convention is consistent with slice(), at(), and other index-accepting array methods, so the mental model transfers across the standard library.
Using toSpliced() (Immutable)
The toSpliced() method (ES2023) works identically but returns a new array without modifying the original:
const original = [1, 2, 3, 4, 5];
const modified = original.toSpliced(1, 2, 99);
console.log(original);
// [1, 2, 3, 4, 5] — unchanged
console.log(modified);
// [1, 99, 4, 5]
toSpliced() is available in all modern engines (Chrome 110+, Firefox 115+, Node 20+) and is the recommended path for new code where mutation is not required. If you are targeting older runtimes, a polyfill or the manual slice-and-concat pattern can fill the gap. The method name mirrors toSorted() and toReversed(), which form a family of non-mutating array methods introduced in ES2023.
Common Patterns
Removing first element
const arr = [1, 2, 3];
arr.shift(); // slower, reindexes
// Better:
arr.splice(0, 1);
Using splice(0, 1) to remove the first element is equivalent to shift() but makes the intent more explicit — the method signature clearly states “remove one element at index zero.” For bulk removals from the front, splice(0, n) removes n elements in a single call, whereas shift() would require a loop.
Removing last element
const arr = [1, 2, 3];
arr.pop(); // faster for just removing
arr.splice(-1, 1); // equivalent but slower
For removing just the last element, pop() is the idiomatic choice because it is O(1) and returns the removed value directly. splice(-1, 1) accomplishes the same thing but shifts nothing (the element is already at the end), so the performance difference is negligible in practice. However, pop() signals intent more clearly to readers of the code.
Insert at specific position
function insertAt(array, index, ...items) {
array.splice(index, 0, ...items);
}
const nums = [1, 2, 5];
insertAt(nums, 2, 3, 4);
console.log(nums); // [1, 2, 3, 4, 5]
Wrapping splice(index, 0, ...items) in a helper like insertAt makes the insertion intent self-documenting. The spread operator unpacks the items so they are inserted as individual elements rather than as a nested array. For inserting a single array as an element (not its contents), omit the spread and pass the array directly.
Mutation and immutable alternatives
splice() mutates the array in place. If you need a non-mutating version, ES2023 introduced toSpliced(), which returns a new array and leaves the original intact:
const arr = [1, 2, 3, 4, 5];
const mutated = arr.splice(1, 2, 99); // arr is now [1, 99, 4, 5]
const original = [1, 2, 3, 4, 5];
const copy = original.toSpliced(1, 2, 99); // original unchanged: [1, 2, 3, 4, 5]
console.log(copy); // [1, 99, 4, 5]
Use toSpliced() in React state updates and anywhere immutability matters.
Why splice() is still important
splice() remains the right choice when you want to edit an array in place and keep the same reference alive. That is useful in low-level data structures, small scripts, and mutation-heavy code where copying would add unnecessary work. Because it can remove, insert, and replace in one call, it is also the most direct API for list editing. The trade-off is mutation, so it fits best when the array is not shared across state boundaries.
Negative indices
When start is negative, it counts from the end: -1 is the last element, -2 is second-to-last, and so on. If the absolute value exceeds the array length, start is treated as 0.
const arr = ['a', 'b', 'c', 'd'];
arr.splice(-1, 1); // removes last element
console.log(arr); // ['a', 'b', 'c']
Return value
splice() returns an array of the removed elements. If deleteCount is 0, the return value is an empty array. The return value is often ignored, but it is useful when you want to both remove elements from one array and collect them for use elsewhere.
const queue = [1, 2, 3, 4, 5];
const batch = queue.splice(0, 3); // take first 3
console.log(batch); // [1, 2, 3]
console.log(queue); // [4, 5]
Choosing Between splice() and toSpliced()
If other code holds the array reference, toSpliced() is usually safer because it preserves the original. If you own the array and want a single in-place edit, splice() is simpler and often faster. The two methods answer the same logical question, but they differ in ownership: are you updating shared state, or are you editing a local array that no one else depends on? That decision usually tells you which method to choose.
Performance
splice() is O(n) in the worst case because all elements after the insertion or deletion point must be shifted. Adding or removing at the beginning of a large array is the most expensive case. If you need frequent insertions and removals at arbitrary positions, consider using a linked list structure or keeping the array sorted and using binary search to find the insertion point.
For simply removing all elements from an array, setting array.length = 0 is faster than splice(0).
See Also
- Array.prototype.filter() — non-mutating removal by condition
- Array.prototype.toSpliced() — immutable version
- Array.prototype.shift() — remove the first element