jsguides

Array.prototype.pop()

pop()

pop() removes the last element from an array and returns that element. It modifies the array in place, reducing its length by 1. This method is the counterpart to push() and together they implement a stack data structure.

Syntax

arr.pop()

Takes no parameters. Returns the removed element, or undefined if the array is empty.

pop() is deliberately simple — no arguments, one return value, one side effect. It always operates on the last index (array.length - 1), so the call is unambiguous. The return value is the element itself, not wrapped in any container, which makes it straightforward to chain with other operations.

Examples

Basic usage

const fruits = ["apple", "banana", "cherry"];

const last = fruits.pop();
console.log(last);      // "cherry"
console.log(fruits);   // ["apple", "banana"]

pop() returns the removed element itself, not the shortened array. This means you can capture and use the popped value immediately — assign it to a variable, pass it to a function, or store it elsewhere. The original array is modified in place, so subsequent operations see the shorter array.

Working with empty arrays

const empty = [];
const result = empty.pop();

console.log(result);   // undefined
console.log(empty);    // []

pop() on an empty array returns undefined without throwing — a deliberate design choice that avoids the need for a length guard in simple loops. The array itself remains empty, so a second pop() call also returns undefined. This makes while (arr.length) a clean idiom for draining an array from the end.

Processing elements from the end

const items = ["a", "b", "c"];

while (items.length > 0) {
  console.log(items.pop());
}
// Output: c, b, a

Processing from the end preserves the original array order in reverse — last element first, first element last. This is the natural iteration direction for a stack: the most recently added item is the next one out. When you don’t need the values after processing, pop() avoids the memory overhead of maintaining a separate index variable.

Clearing an array efficiently

const arr = [1, 2, 3, 4, 5];
while (arr.pop()) {
  // removes elements until array is empty
}
console.log(arr); // []

The while (arr.pop()) loop stops when pop() returns undefined — the last call pops the final truthy element, then the condition evaluates to undefined and the loop exits. This only works when the array has no falsy values (0, "", false) stored in it, because those would halt the loop early.

Stack Implementation

Arrays with pop() naturally form a last-in-first-out (LIFO) stack:

class Stack {
  constructor() {
    this.items = [];
  }
  
  push(item) {
    this.items.push(item);
  }
  
  pop() {
    return this.items.pop();
  }
  
  peek() {
    return this.items[this.items.length - 1];
  }
  
  isEmpty() {
    return this.items.length === 0;
  }
}

const stack = new Stack();
stack.push(1);
stack.push(2);
stack.push(3);
console.log(stack.pop()); // 3
console.log(stack.pop()); // 2
console.log(stack.isEmpty()); // false

The Stack class wraps an array and exposes only the LIFO interface — push, pop, peek, and isEmpty. This prevents accidental access to the middle of the stack. Because both push() and pop() operate on the end of the array, every operation is O(1). You can swap in a linked list later without changing the public API.

Practical: parsing delimited string

function parseCSV(csv) {
  const result = [];
  let current = '';
  
  for (const char of csv) {
    if (char === ',') {
      result.push(current);
      current = '';
    } else {
      current += char;
    }
  }
  // Don't forget the last field
  result.push(current);
  
  return result;
}

console.log(parseCSV("a,b,c,d")); // ['a', 'b', 'c', 'd']

This parser builds fields character by character, pushing completed fields onto an array each time it hits a delimiter. The push() at the end captures the final field after the last comma. While pop() is not used here directly, this pattern sets up the complementary operation: use pop() to remove the last field if you later need to undo it.

Removing falsy values from end

const data = [1, 2, 3, null, undefined, false];

while (data.length > 0 && !data[data.length - 1]) {
  data.pop();
}
console.log(data); // [1, 2, 3]

The loop checks both conditions: the array must have elements remaining, and the last element must be falsy. As soon as either check fails, the loop stops. This approach trims trailing junk without touching the valid data at the front. It is efficient because each pop() call is O(1) and the loop only removes what needs removing.

Getting array without last element

const items = [1, 2, 3, 4, 5];
const allButLast = [...items];
allButLast.pop();
console.log(allButLast); // [1, 2, 3, 4]

Behavior Notes

  • Returns undefined on empty arrays — always check length if unsure
  • Returns the removed element, not the new array
  • This method modifies the original array (mutating method)
  • Works on array-like objects with length property

Performance

pop() is O(1) constant time — it simply decrements the array length. Unlike shift() which must move all remaining elements, pop() is very efficient.

When pop() is the better choice

pop() is the natural fit when your data behaves like a stack or when the newest item is the one you want to remove. It keeps the code simple because the end of the array is the place where pushes happened last. That makes pop() a good choice for undo stacks, recent-history lists, and any workflow that reads backward from the newest item.

Avoiding empty-array surprises

The return value is undefined when the array is empty, so code that depends on the removed value should check the array length first or handle undefined explicitly. That matters when undefined could also be a valid stored element. A small guard makes the intent clearer and avoids confusing an empty array with a legitimate stored value.

pop() vs shift()

pop() removes from the end; shift() removes from the beginning. The difference matters for performance: pop() is O(1) because no elements need to move. shift() is O(n) because every remaining element must be shifted to fill index 0.

const arr = [1, 2, 3, 4, 5];

arr.pop();   // removes 5 — O(1), no reindexing needed
arr.shift(); // removes 1 — O(n), indices 1-4 all shift down by 1

When building a queue (first-in-first-out), shift() is functionally correct but slow for large arrays. Consider a deque or linked-list structure if queue performance matters. Stacks with push() and pop() are always O(1).

The performance difference stems from how JavaScript engines store arrays in memory. pop() only changes the length property, while shift() must physically move every remaining element to close the gap at index 0.

Avoiding pop() in immutable code

pop() mutates the original array, which breaks patterns where you need to preserve the original (React state, Redux reducers, functional pipelines). Use slice() instead:

const original = [1, 2, 3, 4];

// Mutable — modifies original
const last = original.pop();

// Immutable — creates a new array
const withoutLast = original.slice(0, -1);
const lastItem = original[original.length - 1];

For ES2023+, toSpliced(-1, 1) returns a new array with the last element removed without touching the original.

Some libraries like Immer and Immutable.js provide their own immutable alternatives. The key trade-off is memory: immutable approaches allocate a new array each time, while pop() reuses the same backing store. For small arrays in render-heavy code, immutability simplifies reasoning; for large arrays in hot loops, pop() is far cheaper.

pop() on array-like objects

pop() can be called on array-like objects with a length property using Array.prototype.pop.call():

const obj = { 0: 'a', 1: 'b', 2: 'c', length: 3 };
Array.prototype.pop.call(obj);
// returns 'c', obj.length becomes 2

See Also