Array.prototype.slice()

The non-mutating twin of splice, and one letter away from it. slice COPIES a range out; splice CUTS one out. Confusing them is the single most common Array mistake after sort.

Array methodES3 (1999)Live demo
Common call
items.slice(0, 3)
Returns
a new array; the original is untouched
Replaces
[...items] for a shallow copy — slice() with no args does it
Watch out
end is EXCLUSIVE, and the copy is SHALLOW
array.slice([start[, end]])
→ Array

Demo

Live evaluation
Try:
Inputs
itemsnumber[]numbers, comma separated
startnumberstart index
endnumberend index (exclusive)
Output
[1, 2, 3, 4, 5].slice(1, 3)
[2, 3]

slice(1, 3) gives you elements 1 and 2 — the element at index 3 is excluded, which is why the result has exactly end minus start elements. A negative start counts from the back, so -2 takes the last two. The two degenerate cases return empty rather than erroring: start equal to end selects nothing, and an end BEFORE the start also gives an empty array instead of reversing. An end past the array simply stops at the end.

Parameters

NameTypeRequiredDescription
startnumberno (0)Index to start at. Negative counts from the end, so -2 means "two from the back". Beyond the length gives an empty array.
endnumberno (length)Index to stop BEFORE — the element at this index is not included. Negative counts from the end.

Return value

Array — A NEW array holding elements from start up to but NOT including end. The original is never modified.

Common patterns

Shallow-copy an array
The classic idiom, now usually written as a spread.
const copy = items.slice();
const copy2 = [...items];
Copy before a mutating method
Protects the original from sort, reverse or splice.
const sorted = items.slice().sort((a, b) => a - b);
Take the last N elements
A negative start is the tidy way.
const lastThree = items.slice(-3);

Examples

1. Middle range
[1, 2, 3, 4, 5].slice(1, 3)
Returns
[2, 3]
2. Last two
[1, 2, 3, 4, 5].slice(-2)
Returns
[4, 5]
3. Backwards is empty
[1, 2, 3, 4, 5].slice(3, 1)
Returns
[]
4. Past the end
[1, 2, 3].slice(0, 99)
Returns
[1, 2, 3]
5. Full copy
[1, 2, 3].slice()
Returns
[1, 2, 3]
6. Original untouched
const a = [1, 2, 3]; a.slice(0, 1); a
Returns
[1, 2, 3]

Pitfalls

1. slice and splice are one letter apart and opposite
slice returns a copy and leaves the original alone; splice mutates the original and returns what it REMOVED. A typo between them compiles fine and corrupts your data quietly.
splice mutates
const a = [1, 2, 3];
const b = a.splice(0, 2);
a
[3] // a was gutted
slice copies
const a = [1, 2, 3];
const b = a.slice(0, 2);
a
[1, 2, 3]
2. end is exclusive
slice(0, 3) gives three elements, indices 0 through 2. Expecting the element at end to be included is an off-by-one that shows up as a missing last item.
Missing the last
[1, 2, 3, 4].slice(0, 2)
[1, 2] // not [1, 2, 3]
Go one further
[1, 2, 3, 4].slice(0, 3)
[1, 2, 3]
3. The copy is shallow
A new outer array, but the SAME inner objects. Mutating a nested object through the copy changes it in the original too — a frequent surprise when "I copied it first".
Shared objects
const a = [{n: 1}];
const b = a.slice();
b[0].n = 99;
a[0].n
99
Deep copy
const b = structuredClone(a);
fully independent
4. A backwards range gives empty, not reversed
slice(3, 1) does not reverse anything — it returns an empty array. Computing indices that can cross over therefore fails silently rather than loudly.
Silently empty
[1, 2, 3, 4].slice(3, 1)
[]
Order them
[1, 2, 3, 4].slice(Math.min(a, b), Math.max(a, b))
the intended range

When to use

Use it
  • Copying part of an array without touching the original
  • Shallow-copying a whole array
  • Taking the first or last N elements
  • Guarding an array before a mutating method like sort
Reach for something else
  • You want to REMOVE elements → splice, or filter for a copy
  • You need independent nested objects → structuredClone
  • Selecting by a test rather than by position → filter

Notes

Complexity
O(n) in the size of the slice
Return
A new array; the original is never modified
CPython impl
V8: Builtins-array-slice.tq — fast path for packed arrays
Memory
Allocates a new array holding references to the same elements
Thread-safe
Single-threaded; the source is only read

FAQ

slice copies a range into a new array and leaves the original alone. splice removes (and optionally inserts) elements IN the original, and returns the removed ones. One letter, opposite effects on your data.

const a = [1, 2, 3];
a.slice(0, 2);   // [1, 2], a unchanged
a.splice(0, 2);  // [1, 2], a is now [3]

History

ES3
slice standardised in 1999, mirroring String.prototype.slice.
ES2015
Spread syntax gave [...items] as a more readable shallow copy.