Updated

In JavaScript, when it comes to manipulating the order of elements within an array, reverse() and toReversed() are two commonly used methods, each having its unique functionality and application.

Old school reverse()

The reverse() method, a member of JavaScript’s Array.prototype, alters the order of the array’s elements, essentially flipping them. This method performs the operation in-place, implying that it directly modifies the original array.

Let’s consider the example below:

let fruits = ['🍎', '🥭', '🍍'];
console.log(fruits); // Output: ['🍎', '🥭', '🍍']

let reversedFruits = fruits.reverse();
console.log(reversedFruits); // Output: ['🍍', '🥭', '🍎']

// Note: reverse() mutates the original array.
console.log(fruits); // Output: ['🍍', '🥭', '🍎']

In the above code, after applying reverse(), the original fruits array is also reversed. This is because reverse() is a destructive method and modifies the original array in-place.

Introducing toReversed() 🥳

In contrast to reverse(), the toReversed() method does not mutate the original array. Instead, it creates a new array, mirroring the elements of the original array in reverse order. This method comes handy when preserving the initial order of elements is crucial.

Let’s consider a similar example:

let numbers = [10, 20, 30];
console.log(numbers); // Output: [10, 20, 30]

let reversedNumbers = numbers.toReversed();
console.log(reversedNumbers); // Output: [30, 20, 10]

// toReversed() is non-destructive -- the original array remains unchanged.
console.log(numbers); // Output: [10, 20, 30]

In this example, the original numbers array remains unaffected after applying the toReversed() method, exhibiting its non-destructive nature.

Handling sparse arrays with toReversed()

An additional feature of toReversed() is its behaviour with sparse arrays. In JavaScript, a sparse array is an array where some elements are missing. The toReversed() method treats empty slots in sparse arrays as if they hold the undefined value.

console.log([10, , 30].toReversed()); // Output: [30, undefined, 10]

Here, the empty slot in the array is considered as undefined when reversed.

When did the toReversed() method become available?

To enhance the adaptability and fluidity of array manipulation in JavaScript, the ECMAScript 2023 specification brings about a significant proposal named Change Array by Copy.

This proposal enriches the set of methods on Array.prototype by introducing a suite of functions that operate on the array and return a new copy, instead of manipulating the original array. The newcomers to this function suite include toReversed(), toSorted(), toSpliced(), and an additional method named with().

These methods are designed to mirror the behavior of existing methods reverse(), sort(), and splice(), and the typical array element replacement operation performed using bracket notation. However, these new methods ensure that the original array remains unaltered.

toSorted()

The toSorted() method, just like sort(), arranges the array elements in a certain order. The crucial difference is that it does not modify the original array.

let jumbledNumbers = [30, 10, 20];
console.log(jumbledNumbers); // Output: [30, 10, 20]

let orderedNumbers = jumbledNumbers.toSorted();
console.log(orderedNumbers); // Output: [10, 20, 30]

// The original array remains unchanged
console.log(jumbledNumbers); // Output: [30, 10, 20]

toSpliced()

Similarly, toSpliced() acts as a non-destructive version of splice(). It returns a new array, incorporating the changes specified by the arguments, while the original array stays intact.

let oldArray = ['🍎', '🍌', '🥭'];
console.log(oldArray); // Output: ['🍎', '🍌', '🥭']

// In here we just say, start from index 1 and delete 0 elements, and insert '🍊'
let newArray = oldArray.toSpliced(1, 0, '🍊');
console.log(newArray); // Output: ['🍎', '🍊', '🍌', '🥭']

// The original array remains unchanged
console.log(oldArray); // Output: ['🍎', '🍌', '🥭']

with()

Additionally, the with() method is an invaluable tool that replaces an element at a specified index with a given value and returns a new array, without touching the original array.

let initialFruits = ['🍎', '🍌', '🥭'];
console.log(initialFruits); // Output: ['🍎', '🍌', '🥭']

let updatedFruits = initialFruits.with(1, '🍊');
console.log(updatedFruits); // Output: ["🍎", "🍊", "🥭"]

// The original array remains unchanged
console.log(initialFruits); // Output: ['🍎', '🍌', '🥭']

The motivation behind these new methods

Incorporating these methods in the language specification echoes the increasing emphasis on promoting functional programming styles in JavaScript, where data is usually treated as immutable. This development is a welcome addition for developers who frequently need to perform operations on arrays but wish to keep the original arrays unmodified.

For me personally, these new features significantly simplify array manipulation, particularly in scenarios where avoiding side effects is critical. By preventing accidental mutations, these methods make the code more predictable and easier to reason about, which is a key factor in reducing bugs and enhancing code readability.

Conclusion

The ECMAScript 2023 ‘Change Array by Copy’ proposal introduces four powerful methods that align JavaScript with modern functional programming practices: toReversed(), toSorted(), toSpliced(), and with(). These non-destructive alternatives keep your original arrays untouched, making code more predictable and safer, especially when working with frameworks like React that rely on immutability.

Supported in modern browsers (Chrome 110+, Firefox 115+, Safari 16+), in my opinion, these methods should be your default choice for array manipulation. Use the traditional mutating methods only when you explicitly need in-place modification.

Happy coding! 🚀

Well, now what?

You can navigate to more writings from here. Connect with me on LinkedIn for a chat.