How many ways can we reverse an Array?

How many ways can we reverse an Array?

ยท

3 min read

There's a Stage 3 proposal to add several array methods including Array.prototype.toReversed, which will create a reversed copy of the array. This will be a welcome addition since Array.prototype.reverse mutates the array, which often is not what we want.

I thought it might be fun to explore some of the ways we can implement this new method using currently available language features. Of course, there is already a package on npm that polyfills this function, so this is mostly an exercise for learning purposes only.

Reversing a copy of the array

The most straightforward way to do this is make a copy of the array, and then call reverse on it. This has the end result of not mutating the original array, but it does mutate the copy, so this is a bit of a cheat.

Using slice

Array.prototype.slice will create a shallow copy of the array. This means that the references to each array element is copied into a new array. Reversing this copy mutates the new array by reordering items, but won't affect the ordering of the original array, or modify any of its elements.

const reversed = originalArray.slice().reverse();

Using array spread

We can use the spread syntax to create a copy of the array, then reverse it.

This is essentially doing the same thing as the slice approach. Make sure the .reverse call is outside the brackets, otherwise we'll be mutating the array then copying it.

// โœ… Copies the array, then mutates the copy
const reversed = [...originalArray].reverse();

// โŒ Mutates the original array, then copies
const reversed = [...originalArray.reverse()];

Using map

We can build the reversed array by mapping each element to the corresponding element at the other end of the array:

  • element 0 becomes element n - 1
  • element 1 becomes element n - 2
  • etc.

The new element is calculated by subtracting the current index from the last index. For this we can call map on the array:

const reversed = originalArray.map((el, index) => 
  originalArray[originalArray.length - 1 - index]
);

Building the array in reverse order

This one, again, is a partial cheat if we want to avoid mutation since we are mutating the new array on each turn of the loop. In most cases, this is probably acceptable as long as the original array remains unchanged.

const reversed = [];
originalArray.forEach(el => reversed.unshift(el));

Using reduce

If we want to be purists and not mutate anything, we can use reduce to reverse the array. For small arrays it probably doesn't matter, but keep in mind that we are going to increase memory usage, since a new array is created each time through.

This is a good exercise for understanding how reduce works but probably not an ideal version to use in a production app.

const reversed = originalArray.reduce((result, el) => [el, ...result], []);

We start with an empty array. For each element in the array, we create a new array with that element at the beginning, and spread the previous result, creating a new array. When the loop is complete, we'll have the new reversed array.

Which to use?

For smaller arrays, analyzing differences between these approaches is probably an exercise in premature optimization. In such cases I usually prefer a more readable approach, such as the spread syntax:

const reversed = [...originalArray].reverse();