NodeJS array spread operator […] is slower than its older counter parts

I have been using redux quite a lot lately. It definitely makes my code highly predictable and my data flow almost flawless. Immutability is synonymous with redux. You shouldn’t update an array or a object directly while returning a new state from a reducer. Hence, we are bound to clone an array (slice) and/or concat to it whenever we need to add/remove/update an item from an array. The array spread operator […] provides a very readable syntax to perform this operation.

// Add an item to a list
return [...list, n];
// Remove an item from a list
return [
...list.slice(0, index),
...list.slice(index + 1),
];
// Update an item on a list
return [
...list.slice(0, index),
n,
...list.slice(index + 1),
];

I had been using redux on my server side logic as well, so I wanted to check if there was anyway to optimize the mutation. For example, I assumed cloning the source array and then updating that array should be faster than updating using the spread operator as shown above. So instead I used a code which looked like:

// Update an item on a list
const clone = list.slice();
clone[index] = n
return clone;

Then I ran a benchmark code to check which code ran faster. I was taken back by the result. With a list (array) of a length around 500 items, the difference was more than 60 times. On my machine with around 500,000 iterations, it took 0.372 microseconds per update using the later technique whereas with the former it took 30.088 microseconds per operation. I added another method on my benchmark, which just replaced the spread syntax to its older counterpart using slice and concat. Basically:

// Update an item on a list
return list.slice(0, index).concat(n).concat(list.slice(index+1));

To my amusement, this version was comparable to the second version with around 1.066 microseconds per operation.

Now, I took it upon myself to see if the spread operator syntax was actually slower in all respect or not. And it sure was. Even with a simple cloning, list.slice() was 80 times faster than […list] with list size being 500. The difference was not significant with smaller lists.

The benchmarking code that I used can be found here https://gist.github.com/syaau/bb328aead4943f7d8a2e156f46845d16. I got the following results on system with Intel Core i7 2.2 GHz using node 7.4.0:

Running benchmark with array size 500 and index 250
 Array clone with slice 0.326 microseconds per operation
 Array clone with spread operator 28.596 microseconds per operation
 Array addition with plain concat 1.634 microseconds per operation
 Array addition with spread operator 30.22 microseconds per operation
 Array addition with slice and push 0.98 microseconds per operation
 Array removal with slice and concat 0.852 microseconds per operation
 Array removal with spread operator 29.476 microseconds per operation
 Array removal with slice and splice 0.53 microseconds per operation
 Array update with slice and concat 1.138 microseconds per operation
 Array update with spread operator 30.19 microseconds per operation
 Array update with slice and assign 0.476 microseconds per operation
Running benchmark with array size 10 and index 5
 Array clone with slice 0.134 microseconds per operation
 Array clone with spread operator 0.748 microseconds per operation
 Array addition with plain concat 0.238 microseconds per operation
 Array addition with spread operator 0.806 microseconds per operation
 Array addition with slice and push 0.168 microseconds per operation
 Array removal with slice and concat 0.406 microseconds per operation
 Array removal with spread operator 1.11 microseconds per operation
 Array removal with slice and splice 0.266 microseconds per operation
 Array update with slice and concat 0.592 microseconds per operation
 Array update with spread operator 1.082 microseconds per operation
 Array update with slice and assign 0.128 microseconds per operation

I would definitely like someone to cross verify what I found. It would be great if someone could shed a light on this. My assumption was the spread syntax was just a syntatical makeup.

[P.S. The results were not better in FireFox either.]