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 mutatedWalk 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.