Array.prototype.shift()
pop from the other end — but with a cost pop does not have. Every remaining element shifts down one index, which makes a drain loop quadratic.
Common call
const first = queue.shift()
Returns
the removed element, or undefined
Replaces
reading items[0] then removing it
Watch out
O(n) per call — a shift-drain over a big array is O(n²)
array.shift()
→ any
Demo
Live evaluation
Try:
Inputs
itemsnumber[]numbers, comma separated
Output
[1, 2, 3].shift()
1
The FIRST element is removed and returned — the mirror of pop. The array is modified in place and is not what comes back. An empty array gives undefined rather than an error. What the demo cannot show is the cost: unlike pop, every surviving element has to move down one index, so each call is proportional to the array length.
Common patterns
FIFO queue
push and shift together, fine for small queues.
queue.push(job); const next = queue.shift();
Drain from the front
Guard with length; watch the cost on large arrays.
while (queue.length) handle(queue.shift());
Destructure instead
Non-mutating, and often what you actually meant.
const [first, ...rest] = items;
Examples
1. Returns the first
[1, 2, 3].shift()
Returns
12. The array after
const a = [1, 2, 3];
a.shift();
a
Returns
[2, 3]3. Empty is undefined
[].shift()
Returns
undefined4. pop is the other end
[1, 2, 3].pop()
Returns
35. Non-mutating
const [first, ...rest] = [1, 2, 3];
rest
Returns
[2, 3]6. Peek instead
[1, 2, 3][0]
Returns
1 // not removedPitfalls
1. It is O(n), and draining is O(n²)
Every call re-indexes the whole array. A while loop shifting a hundred thousand items does billions of moves — the single most common accidental quadratic in JavaScript queue code.
Quadratic drain
while (queue.length) handle(queue.shift());
O(n²) on a large queue
Walk with an index
for (let i = 0; i < queue.length; i++) handle(queue[i]);
O(n)
2. Empty gives undefined, not an error
Exactly like pop. Shifting without checking the length yields a phantom undefined rather than failing, which turns a bug into silently processed garbage.
Phantom element
while (true) handle(queue.shift());
handles undefined forever
Check the length
while (queue.length) handle(queue.shift());
stops cleanly
3. It mutates a shared array
Same hazard as every in-place method: props, state and cached arrays all change for everyone, with the reference unchanged so identity checks see nothing.
Mutates state
state.queue.shift();
same reference, no re-render
Slice instead
setQueue(state.queue.slice(1));
new array
When to use
Use it
- Small FIFO queues where the cost does not matter
- Removing the first element of an array you own
- Consuming a short argument list front to back
Reach for something else
- Large or hot queues → index forward, or use a real deque
- The array is shared or state → slice(1)
- You only want to READ the first element → items[0]
- You want the rest without mutating → destructuring
Notes
Complexity
O(n) — every remaining element moves down one index
Return
The removed element or undefined; the array is modified in place
CPython impl
V8: Builtins-array-shift.tq — has a fast path for small packed arrays
Memory
No allocation, but the whole backing store is re-indexed
Thread-safe
Single-threaded; mutating a shared array is the hazard here
FAQ
Because array indices are positional. Removing the last element leaves every other index correct; removing the first means element 1 becomes element 0, 2 becomes 1, and so on for the whole array. pop is O(1), shift is O(n).
History
ES3
shift standardised in 1999 alongside push, pop and unshift.