JavaScript Array Mutability: Push, Pop, Shift, Unshift

In JavaScript, arrays are mutable objects, meaning their contents can be altered without creating a completely new array instance in memory. Built-in manipulation methods such as push(), pop(), shift(), and unshift() directly modify the original array in place rather than returning a new one. Understanding how these four methods alter array structure, return values, and impact performance is essential for managing state and avoiding unintended side effects in JavaScript applications.

How JavaScript Handles Array Mutability

When an array is created in JavaScript, it is stored as a reference type in memory. Methods designed to add or remove elements can either be mutating (modifying the underlying memory reference) or non-mutating (returning a new array, such as concat() or slice()).

The methods push(), pop(), shift(), and unshift() are all mutating methods. They change the array’s length property and rearrange its indexed elements directly on the existing reference.

Modifying the End of an Array

push()

The push() method appends one or more elements to the end of an array.

const numbers = [1, 2, 3];
const newLength = numbers.push(4, 5);

console.log(numbers);   // [1, 2, 3, 4, 5] (Original array is mutated)
console.log(newLength); // 5

pop()

The pop() method removes the last element from an array.

const numbers = [1, 2, 3];
const removedElement = numbers.pop();

console.log(numbers);        // [1, 2] (Original array is mutated)
console.log(removedElement); // 3

Modifying the Beginning of an Array

unshift()

The unshift() method adds one or more elements to the beginning of an array.

const numbers = [2, 3];
const newLength = numbers.unshift(0, 1);

console.log(numbers);   // [0, 1, 2, 3] (Original array is mutated)
console.log(newLength); // 4

shift()

The shift() method removes the first element from an array.

const numbers = [1, 2, 3];
const removedElement = numbers.shift();

console.log(numbers);        // [2, 3] (Original array is mutated)
console.log(removedElement); // 1

Summary of Behaviors

Method Position Operation Mutates Original? Return Value Time Complexity
push() End Add element(s) Yes New array length \(O(1)\)
pop() End Remove element Yes Removed element \(O(1)\)
unshift() Beginning Add element(s) Yes New array length \(O(n)\)
shift() Beginning Remove element Yes Removed element \(O(n)\)

Avoiding Unintended Mutations

Because these methods mutate the underlying reference, passing an array to a function that uses these methods will change the data across all scopes referencing that array.

When immutability is required—such as in state management patterns like React or Redux—avoid these mutating methods or create a shallow copy before applying them using the spread syntax ([...array]), Array.from(), or slice(). Alternatively, modern JavaScript offers non-mutating alternatives such as toSpliced(), concat(), or spread operations to create updated array copies safely.