Reverse an Array in JavaScript

Abstract image used to represent Reverse an Array in JavaScript
Image by cdd20.

It's really common to be tasked with reversing an array in JavaScript, whether you're displaying items in reverse order or processing data from end to start. As you will probably know, JavaScript offers the inbuilt .reverse() method, which makes this task simple. However, there is more to reversing arrays than meets the eye, especially when it comes to immutability.

Today, I intend to explore how to reverse arrays in JavaScript, the caveats of using .reverse(), and touch upon some of the older methods that you might encounter for reversing arrays. By the end, you should hopefully understand the best approaches for reversing arrays without unintended side effects.


The .reverse() Method

Any relatively seasoned frontend developer will be familiar with the .reverse() method. This is the most straightforward way to reverse an array in JavaScript, and looks something like this:

const originalArray = [1, 2, 3, 4, 5];
const reversedArray = originalArray.reverse();

console.log(reversedArray);  // Output: [5, 4, 3, 2, 1]

At first glance, this all looks very straightforward and perhaps unusually for JavaScript development very logical. You might appreciate, though; this wouldn't exactly be a very long or interesting article if there wasn't at least one catch. In this case, there's a critical detail to be aware of: .reverse() mutates the original array.

The Mutation Problem

In layman's terms, a mutating method changes the original source data as well (our array). This means that your original (named) variable is now backwards, which can very quickly lead to unexpected behaviour, especially when the same array is referenced elsewhere in your code:

const numbers = [1, 2, 3, 4, 5];
const reversed = numbers.reverse();

console.log(numbers);  // Output: [5, 4, 3, 2, 1] (original array is modified)

As you can see in the example above, even though we've defined a new const (reversed) for the backwards version of the array, the original const (numbers) has also now been reversed (mutated).

This is a side effect that can cause bugs, especially in larger applications where data immutability is crucial.

Reversing Without Mutating

For a new reversed array, use toReversed(). It has been available across current browser engines since July 2023; check your target runtimes if you support older versions. Copying first and calling reverse() remains a useful fallback:

const originalArray = [1, 2, 3, 4, 5];
const reversedArray = typeof originalArray.toReversed === 'function'
  ? originalArray.toReversed()
  : [...originalArray].reverse();

console.log(originalArray);  // Output: [1, 2, 3, 4, 5] (unchanged)
console.log(reversedArray);  // Output: [5, 4, 3, 2, 1]

Both approaches return a new array without changing the original. They are shallow: any objects inside remain the same objects. Empty slots become undefined in both of these new arrays, which differs from calling reverse() directly on a sparse array.

Why Immutability Matters

It may well be that you never intend to use the original const again, so it doesn't matter for your specific usecase. However, immutability helps prevent unintended side effects and makes our code easier to:

  • Debug:

    Since data isn't unexpectedly changing, it's easier to track down issues.
  • Maintain:

    Immutability leads to more predictable code, reducing hidden dependencies.
  • Optimise:

    Many modern frameworks (like React) rely on immutability for performance optimisations.

Alternative Methods of Reversing an Array

The .reverse() method has been available since ECMAScript 1 (1997), so it is safe to say that you are going to struggle to find any JavaScript environment in use today that doesn't support it it quite literally predates even IE6! Nevertheless, it would be amiss of me to not at least explore legacy solutions with JavaScript fundamentals.

Using a for Loop

A backwards for loop is also a perfectly reasonable option. Here is a TypeScript example:

const reverseArray = (arr: number[]): number[] => {
  const result: number[] = [];
  for (let i = arr.length - 1; i >= 0; i--) {
    result.push(arr[i]);
  }
  return result;
};

const original = [1, 2, 3, 4, 5];
console.log(reverseArray(original));   // Output: [5, 4, 3, 2, 1]

Here we simply loop over the original array backwards, pushing our new order into a new variable. This approach doesn't mutate the original array and is still efficient, although perhaps less concise than using the spread operator and .reverse().

Using reduce()

Using reduce() which wasn't introduced until December 2009 as part of ECMAScript 5 certainly isn't going to win us any 'legacy alternative to .reverse()' rewards. Even so, it does offer an alternative that removes mutation, and is worth exploring simply as a way to discuss the way JavaScript works and the many ways it can be used to achieve the same thing. I wouldn't even suggest this is a viable production alternative, just an experiment and discussion point.

So, using reduce() to reverse an array looks like this:

const originalArray = [1, 2, 3, 4, 5];
const reversedArray = originalArray.reduce((acc, curr) => [curr, ...acc], []);

console.log(reversedArray);  // Output: [5, 4, 3, 2, 1]

This version avoids changing the original array, but each step copies the accumulator again. For n elements, that creates quadratic copying work. The earlier loop appends each element once, so its work grows linearly. I would choose the loop or a builtin method when that extra copying serves no purpose.


Wrapping Up

The useful decision is whether the original array should change. Use reverse() when mutation is intended, or toReversed() when you need a new array and your runtime supports it. Copying before reversing remains a straightforward fallback.

Key Takeaways

  • The .reverse() method mutates the original array.
  • Use toReversed() for a new array, or [...array].reverse() as a copying fallback.
  • A backwards for loop is a valid linear alternative. The reduce() example repeatedly copies its accumulator and does quadratic copying work.
  • .reverse() has been available since ECMAScript 1 (1997), so it's universally supported.

Understanding both modern and traditional approaches gives you flexibility and deeper insight into JavaScript's capabilities.


Untangling a delivery problem?

Send the symptoms, constraints, and affected routes. I'll help identify whether the issue sits in the application, platform, content model, deployment path, or search surface.