Ch. 1 · JavaScript

JavaScript Array Methods: Mutating Versus Returning New

Know which array methods change the original in place and which return a new array, and pick the right one to avoid shared-state bugs.

~2 min readbeginnerupdated Oct 5, 2026

Array methods fall into two groups: some mutate the receiver in place and return something else, others leave the receiver untouched and return a new array. Mixing them up causes bugs where a “copy” still changes the original, or where a returned value is assumed to be the modified array.

Before you start

You should be comfortable with arrays and callbacks. This article classifies the common methods; it assumes you know map and filter.

Step-by-step walkthrough

Step 1: Recognize the mutators

push, pop, shift, unshift, splice, sort, reverse, fill and copyWithin change the array in place. sort and reverse are the quiet offenders: they look declarative but reorder the original. If the array is shared state, copy first.

Step 2: Use the returning methods for transforms

map, filter, slice, concat, flat, flatMap and with return a new array and leave the source intact. slice() with no arguments is the idiomatic shallow copy, and toSorted, toReversed, toSpliced and with are the copying counterparts of the mutators.

Step 3: Track what each method returns

splice returns the removed elements, not the remaining array; push returns the new length; sort returns the same, now-reordered array. Assigning the result of splice back onto the variable is a classic off-by-design bug.

Worked scenario

Run this with Node.js. slice protects the original while splice changes it.

const a = [3, 1, 2];
const b = a.slice().sort((x, y) => x - y);
console.log(a); // [3, 1, 2] unchanged
console.log(b); // [1, 2, 3]
console.log(a.splice(1, 1)); // [1] is returned
console.log(a); // [3, 2] is now mutated
JavaScript

Walk through the example

a.slice() creates a copy, and sorting the copy leaves a in its original order. Then a.splice(1, 1) removes one element starting at index 1 and returns the removed [1]; a becomes [3, 2]. The two calls illustrate the two return-value conventions in the same array.

Common mistake

Assuming sort or reverse is non-mutating and accidentally reordering React state or a shared configuration array. Another is writing items = items.splice(...), which replaces the array with the removed elements and silently loses the rest.

Verify the behavior

Sort a copy and assert the original is unchanged. Call splice and assert the return value is the removed slice, not the remainder. Compare reverse() with toReversed() to confirm one mutates and the other does not. Assert push returns the length, not the array.

Interview exercise

You need the top five scores without disturbing the stored list. Which single expression is safest?

Answer and reasoning

Use scores.toSorted((a, b) => b - a).slice(0, 5), or [...scores].sort(...).slice(0, 5) on older runtimes. toSorted copies and sorts without touching the source, and slice takes a copy of the prefix. Using scores.sort(...).slice(0, 5) would work but reorder the stored list as a side effect, which is exactly the shared-state bug to avoid.

Continue learning

See the shallow-copy mechanics in rest and spread gotchas and read the MDN Array reference. Continue with the JavaScript MCQs.

More in JavaScript

read ✓JavaScript · easy

JavaScript Array Sort Comparators

Sort arrays in place with a correct comparator, understand default string ordering and sort stability, and avoid the numeric and string traps.

~3 min readread →
read ✓JavaScript · mid

JavaScript Date and Timezone Pitfalls

Parse and format dates without timezone surprises: zero-based months, date-only versus date-time parsing, and why UTC storage avoids drift.

~3 min readread →
read ✓JavaScript · mid

JavaScript Number Precision and BigInt

Why 0.1 + 0.2 is not 0.3, where safe integer range ends, and when BigInt is the right tool for large identifiers and money.

~2 min readread →
esc