Non-Mutating Array Methods in JavaScript

JavaScript introduced a set of non-mutating array methods in ECMAScript 2023 (ES14) that allow developers to transform arrays without altering the original data. Traditional methods like sort(), reverse(), and splice() mutate arrays in place, which can cause unintended side effects and bugs in state-driven applications. The newer alternatives—toSorted(), toReversed(), toSpliced(), and with()—create and return a shallow copy of the array with the requested changes applied, keeping the original array intact.

Why Non-Mutating Methods Matter

In functional programming and modern frameworks like React, state immutability is crucial. Previously, to avoid mutating an array, you had to manually create a copy using the spread operator ([...arr]) or Array.prototype.slice() before performing operations:

// Old approach
const original = [3, 1, 2];
const sorted = [...original].sort();

The new methods eliminate this boilerplate by handling the copying process internally.

Array.prototype.toSorted()

The toSorted() method is the immutable counterpart to sort(). It returns a new array with the elements sorted in ascending order or according to a provided comparator function.

const numbers = [40, 10, 30, 20];

// Sorts without mutating 'numbers'
const sortedNumbers = numbers.toSorted((a, b) => a - b);

console.log(sortedNumbers); // [10, 20, 30, 40]
console.log(numbers);       // [40, 10, 30, 20]

Array.prototype.toReversed()

The toReversed() method is the non-mutating equivalent of reverse(). It produces a new array with elements in the inverted sequence.

const letters = ['a', 'b', 'c', 'd'];

// Reverses without mutating 'letters'
const reversedLetters = letters.toReversed();

console.log(reversedLetters); // ['d', 'c', 'b', 'a']
console.log(letters);         // ['a', 'b', 'c', 'd']

Array.prototype.toSpliced()

The toSpliced() method replaces splice() when immutability is required. While splice() modifies the target array and returns the deleted elements, toSpliced() returns a completely new array with the additions, removals, or replacements applied.

Its syntax is: toSpliced(start, deleteCount, ...items)

const months = ['Jan', 'Mar', 'Apr', 'May'];

// Insert 'Feb' at index 1 without mutating 'months'
const fullMonths = months.toSpliced(1, 0, 'Feb');

console.log(fullMonths); // ['Jan', 'Feb', 'Mar', 'Apr', 'May']
console.log(months);     // ['Jan', 'Mar', 'Apr', 'May']

Array.prototype.with()

The with() method offers a non-mutating way to update a single value at a specific index. Instead of using bracket notation (such as arr[index] = value), which mutates the array, with() returns a copy containing the updated item.

Its syntax is: with(index, value)

const scores = [85, 90, 78];

// Update the score at index 2 without mutating 'scores'
const updatedScores = scores.with(2, 95);

console.log(updatedScores); // [85, 90, 95]
console.log(scores);        // [85, 90, 78]

Negative indices are also supported, where -1 represents the last item in the array.

Summary

The toSorted(), toReversed(), toSpliced(), and with() methods make data transformations safer and more expressive in JavaScript. By handling array duplication automatically, they simplify code, prevent accidental side effects, and integrate seamlessly into immutable programming workflows.