Reversing a JavaScript array without .reverse() / code explanation

I was working on a problem on Codewars.com and I stumbled upon an interesting solution on StackOverflow. Someone was asking how to reverse an array WITHOUT using .reverse().

Here is one solution someone wrote:

let reverse=a=>[...a].map(a.pop,a)

It helps me to look at it like this:
(but I still don’t completely understand it)

let reverse = (a) => {
    return [...a].map(a.pop, a);
};

Original thread on StackOverflow

I have used the spread operator, but not in this situation. Why is it used here?
Why is .pop used without the parentheses? .pop()?
I also see that the person added the original array as an argument. I know that it is optional and can be done, but reading at MDN, I don’t understand why.

I understand the big picture: map returns a new array and we are “popping” off the elements one at a time from the end of the array. This reverses the array. But, I really couldn’t explain this to someone and I would like to understand.

So here’s my question: Would anyone like to “walk me through this” and enlighten me as to what is going on here?

Here is the code:

let reverse = (a) => [...a].map(a.pop, a);
// [5,4,3,2,1]

The […a] uses the spread operator to make a copy of the array. Why is a copy being made? Consider this alternative code that doesn’t use the spread operator.

let reverse = (a) => a.map(a.pop, a);
// [5,4,3,undefined,undefined]

When you do: reverse([1,2,3]) the map will run once for each item in the array.

With the 1st item in the array, the a.pop gives 3 and the array reduces down to [1,2]
With the 2nd item in the array, the a.pop gives 2 and the array reduces down to [1]
With the 3rd item in the array, it doesn’t exist, so map gives undefined.

That leaves you with a result of [3,2,undefined] which is not what you want.

Instead, you want to pop from a copy of the array. There are older techniques to clone an array, such as using a.slice(0), which works:

let reverse = (a) => a.slice(0).map(a.pop, a);
// [5,4,3,2,1]

So […a] is just a more modern ES6 technique of cloning an array, so that the original array doesn’t get affected by the pop method.

Note though that this function is even more destructive (so to say) than the array .reverse() method, in that clears the original array… mapping over a copy has absolutely no effect here. If you don’t want to modify the original array, you’ll have to pass a copy as the this parameter:

const reverse = a => a.map(Array.prototype.pop, [...a])

(You could also write a.pop here, but personally I like to be explicit when I’m using methods in the prototype directly… it changes the this context anyway. It’s just a bit clearer this way.) :-)

Thanks @m3g4p0p - that’s something that I forgot to investigate.

The spread operator more properly belongs on the second parameter to the map function.

Here’s the original code:

const reverse = a => [...a].map(a.pop, a);
// empties a

The problem as @m3g4p0p rightly pointed out, is that any assigned array that you reverse, end up being emptied because of the a.pop method.

Let’s deal with that in a step-wide fashion. To prevent a.pop from destroying the array, you can make a clone for the second argument of the map function:

const reverse = a => [...a].map(a.pop, [...a]);

And now any variable that contains the array that you are reversing, is now preserved from being changed.
Because the mapping is now occurring on a clone of a, the initial clone is now not required:

const reverse = a => a.map(a.pop, [...a]);
1 Like

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.