Before the individual methods, one classification matters more than any single method's syntax: does it change the original array/object in place, or return a new one and leave the original untouched?
const original = [3, 1, 2];
const sorted = original.sort();
console.log(original); // [1, 2, 3] — sort() mutated the ORIGINAL array too
console.log(sorted === original); // true — it's literally the same array reference, not a copy
Confusing a mutating method for a non-mutating one is one of the most common real-world JavaScript bugs — especially in frameworks like React, which decide whether to re-render by comparing object/array references, not contents. Mutating an array in place leaves its reference identical, so React (or any reference-equality check) sees "nothing changed" and skips the re-render entirely, even though the data did change.
| Category | Methods |
|---|---|
| Mutates the original | .push(), .pop(), .shift(), .unshift(), .splice(), .sort(), .reverse(), .fill(), .copyWithin() |
| Returns a new array/value, original untouched | .map(), .filter(), .reduce(), .slice(), .concat(), .flat(), .flatMap(), spread [...arr], .toSorted(), .toReversed() (newer, non-mutating counterparts) |
Newer non-mutating counterparts (.toSorted(), .toReversed(), .toSpliced(), .with()) now exist alongside the classic mutating methods specifically to give an immutable option without a manual copy — check current runtime/browser support before relying on them in a project with an older target environment.