Array.prototype.slice copies a contiguous range of elements into a new array and leaves the original untouched. The end index is exclusive, negative indices count from the end, and the copy is shallow—nested objects are still shared references. When you need mutating removal or insertion in the middle of an array, use splice instead; for “drop the last element” without mutation, slice(0, -1) pairs naturally with pop semantics.
Tested on: all examples in this tutorial were run with Node.js v20.18.2, and the output shown below each snippet is its exact console output.
Quick reference
Use this table for array slicing javascript: mutability, return shape, and typed-array buffer sharing.
| Method | Mutates original? | Typical return |
|---|---|---|
slice |
No | New array (or typed array) with selected elements |
splice |
Yes | Array of removed elements |
subarray (typed) |
No (but shares buffer) | New view on same buffer |
filter |
No | New array matching predicate |
slice(start, end) — javascript slice array basics
end is exclusive. The original array is unchanged.
let myArray = [1, 2, 3, 4, 5];
let slicedArray = myArray.slice(1, 3);
console.log(slicedArray, myArray);[ 2, 3 ] [ 1, 2, 3, 4, 5 ]Negative indices — js array slicing
Negative start / end count backward from length, so you can trim ends without computing indexes by hand.
console.log([1, 2, 3, 4, 5].slice(1, -1));
console.log([1, 2, 3, 4, 5].slice(-2));[ 2, 3, 4 ]
[ 4, 5 ]Shallow copy of the whole array — slice array javascript clone
Calling slice() with no arguments copies the whole array (shallowly).
console.log([1, 2, 3].slice());[ 1, 2, 3 ]Nested structures are still shared by reference; slice is not a deep clone.
splice — not the same as slice (array slicing javascript pitfall)
splice(start, deleteCount) removes deleteCount elements at start and returns those elements; it mutates the array.
let myArray = [1, 2, 3, 4, 5];
let removed = myArray.splice(1, 3);
console.log(removed, myArray);[ 2, 3, 4 ] [ 1, 5 ]This is not “slice with inclusive end”; the second argument is how many to delete, not an end index.
Typed arrays: subarray vs slice
TypedArray.prototype.subarray returns a view on the same buffer (mutations can alias the original). slice on a typed array copies the range into a new typed array.
const u = new Uint8Array([1, 2, 3, 4]);
const s = u.slice(1, 3);
s[0] = 99;
const u2 = new Uint8Array([1, 2, 3, 4]);
const sb = u2.subarray(1, 3);
sb[0] = 88;
console.log("sliceBuf", u, s);
console.log("subBuf", u2, sb);sliceBuf Uint8Array(4) [ 1, 2, 3, 4 ] Uint8Array(2) [ 99, 3 ]
subBuf Uint8Array(4) [ 1, 88, 3, 4 ] Uint8Array(2) [ 88, 3 ]Plain slice on a Uint8Array (same numeric range as the opening subarray example):
const myArray = new Uint8Array([10, 20, 30, 40, 50]);
let slicedArray = myArray.slice(1, 4);
console.log(slicedArray);Uint8Array(3) [ 20, 30, 40 ]filter — index-based slice-like ranges
Prefer slice when you only need a contiguous index range; use filter when the condition is more complex.
let myArray = [1, 2, 3, 4, 5];
let slicedArray = myArray.filter((_, index) => index >= 1 && index < 3);
console.log(slicedArray);[ 2, 3 ]Generic Array.prototype.slice.call — js slice array on array-like
slice is generic: with .call, you can materialize an array from an array-like object with a length.
console.log(Array.prototype.slice.call({ 0: "a", 1: "b", length: 2 }, 0, 1));[ 'a' ]Summary
slice(start, end)copies a half-open range and never mutates the source array.- Negative indices count from the end;
slice()clones the whole array shallowly. splicedeletes in place and returns removed elements—different arguments thanslice.- On typed arrays,
subarrayshares a buffer;slicecopies. Usefilteronly when selection is not a simple range.
References
MDN references for slice, splice, typed-array views, and filter.
- MDN:
Array.prototype.slice() - MDN:
Array.prototype.splice() - MDN:
TypedArray.prototype.subarray() - MDN:
TypedArray.prototype.slice() - MDN:
Array.prototype.filter()
