28

I was trying to understand what is the difference between spread syntax vs slice method in the following approach.

suppose I want to make an actual copy of an array, I can probably easily do it using spread syntax

var fruits = ["Banana", "Chips" , "Orange", "Lemon", "Apple", "Mango"]
var newCitrus = [...fruits]

If I console.log this

["Banana", "Chips", "Orange", "Lemon", "Apple", "Mango"] 

but I can also create a copy of an array using the slice method. Considering the same array above, if I do something like this...

var citrus = fruits.slice(0);

and then console log it, it will give me exactly the same array which I would've got through spread syntax

["Banana", "Chips", "Orange", "Lemon", "Apple", "Mango"] 

Since both of them takes about the same time to code/write, What is the difference here? which approach should I usually choose?

Patrick Roberts
  • 49,224
  • 10
  • 102
  • 153
Alwaysblue
  • 9,948
  • 38
  • 121
  • 210
  • 1
    `This will console.log` Huh? No, it won't. Why is that different from the `fruits`? Also, you're not using `splice` anywhere in your code – CertainPerformance Jul 03 '18 at 23:54
  • `slice` is absolutely not the same as `splice`. – ASDFGerte Jul 03 '18 at 23:55
  • @ASDFGerte Ohh sorry my bad. Wrote that by accident. – Alwaysblue Jul 03 '18 at 23:56
  • As with many things in life there are often numerous ways to acheive same end result. Use what feels best. Without running perf tests this is primarily an opinion question – charlietfl Jul 03 '18 at 23:57
  • 16
    spread operator is about 5% **faster** than slice in Firefox - spread operator is about 60% **SLOWER** than slice in Chrome - so, you would use spread operator to convince people that Chrome is slower than Firefox – Jaromanda X Jul 03 '18 at 23:58
  • 2
    `slice` allows for more control which part of the array to take, whereas the spread operator allows for quick "pasting" into arrays, e.g. `["other", "elements", ...fruits]`. – ASDFGerte Jul 03 '18 at 23:58
  • @charlietfl in the above case, they both have absolutely no difference? – Alwaysblue Jul 03 '18 at 23:58
  • though, there's also `.concat` - which is about the same speed in firefox - and about 75% slower than spread ... so if you really want to slow chrome down, use concat – Jaromanda X Jul 04 '18 at 00:00
  • 11
    @Mark_M - so, not `[].concat([...arr].slice())` – Jaromanda X Jul 04 '18 at 00:03
  • @JaromandaX check the first answer :) – Alwaysblue Jul 04 '18 at 00:45
  • @JaromandaX spread is _not an operator_, it is a _syntax_ ;) – Patrick Roberts Sep 07 '18 at 20:06
  • @PatrickRoberts - is that important? the URL for MDN documentation includes `Reference/Operators/Spread_syntax` ... so, you could argue it's a "spread syntax operator" - but in the end it doesn't even matter – Jaromanda X Sep 08 '18 at 01:23
  • 2
    @JaromandaX it actually is important. I've seen people ask things like "why can't I do `var args = ...arguments;`" and the answer is _because it's not an operator_. – Patrick Roberts Sep 08 '18 at 06:17
  • fair enough @PatrickRoberts I didn't think of the implications of calling it an operator :p – Jaromanda X Sep 08 '18 at 06:23

6 Answers6

29

Performance aside slice is just a function on Array.prototype so it will work only for arrays and strings. Spread syntax on the other hand will work for any iterable (object which satisfy iterable protocol) so it will work out of the box on any String, Array, TypedArray, Map and Set. You can also easily create custom iterables.

There is also a difference when it comes to sliceing and spreading arrays with holes (sparse arrays). As you can see below, slice will preserve sparseness while spread will fill holes with undefined.

Array(3)         // produces sparse array: [empty × 3]
Array(3).slice() // produces [empty × 3]
[...Array(3)]    // produces [undefined, undefined, undefined]

Spread syntax can also be used to make shallow clones of objects:

const obj = { foo: 'bar', baz: 42 };
const clone = { ...obj };
obj.foo === clone.foo // true
obj.baz === clone.baz // true
obj === clone         // false (references are different)
asdasd
  • 63
  • 1
  • 8
Bartosz Gościński
  • 1,468
  • 1
  • 16
  • 28
18

Measuring in Chrome shows that slice is far more performant than the spread operator, with 67M operations per second against 4M operations per second. If you're building for Chrome or an Electron app (which uses Chromium) I'd go for slice, especially for big data and real time applications.

Measure results

EDIT:

It seems like the Spread operator is now much faster, albeit still slower than Slice:

Newer Measurement Results

  • Ran your benchmark on current Chrome and having 75,333,251 ops/sec vs 68,604,739 ops/sec. Looks like spread operator improved a lot in current version – Sergei Svekolnikov Mar 28 '19 at 14:30
  • Spread Operator is faster in Firefox Safari, and Chrome Mobile IOS – VFDan May 17 '19 at 01:15
  • 1
    Looks like spread is way faster https://measurethat.net/Benchmarks/Show/2667/0/arrayprototypeslice-vs-spread-operator – Sergey Shteyn Aug 16 '19 at 07:24
  • 5
    @SergeyShteyn your benchmark slices `[ 1, 2 ]`. I don't think this is valid. – dominik Jan 09 '22 at 13:30
  • [1, 2] comparison replaced with correct one: https://measurethat.net/Benchmarks/Show/22387/0/arrayprototypeslice-vs-spread-operator-long-2 – OZ_ Dec 04 '22 at 00:00
  • @SergeyShteyn not sure if you're not reading the results backwards (at least for me it shows slice being faster, just tried edge and firefox) – mizuki nakeshu Dec 15 '22 at 12:20
  • @VFDan just tried edge (chromium based) and firefox - edge had 40k/20k slice/spread, firefox had 30k/10k slice/spread, I guess chromium must have done some performance tuning since – mizuki nakeshu Dec 15 '22 at 12:23
5

Performance will depend on the engine where its' running. And as with most Javscript code, it will probably be running in various different engines. So, use whatever feels aesthetically better. For me that's spread.

... is sheer beauty.

If you decide to go with slice, skip the 0, just say .slice().

rmn
  • 1,119
  • 7
  • 18
5

Those two methods aren’t actually equivalent though. Slice is a function on Array.prototype and is aware of the array’s implementation. It will create a very efficient copy. More importantly though, .slice() will preserve the sparseness information of your array.

In contrast, [...Array] will simply create a new array from an iterable view of your existing array. Not necessarily as efficient.

Try this:

var a = [];
a.length = 3;
console.log("slice:", a.slice());
console.log("spread:", [...a]);

With Chrome Browser developer console, I get these results:

slice: (3) [empty × 3]
spread: (3) [undefined, undefined, undefined]

If your array is particularly huge+sparse, array.slice() will be exceptionally fast. [...array] will probably hang your browser.

monarch_dodra
  • 266
  • 4
  • 6
  • The slice() method returns a shallow copy https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice – srgbnd Apr 29 '21 at 07:45
  • Thanks. I removed the word "deep", but it isn’t actually “shallow” either: “It returns a shallow copy *of elements* from the original array. Elements of the original array are copied into the returned array” (emphasis mine). I guess you could say it’s just a standard copy, as you would expect in any reference-based language: The array is new, the references in the array are unchanged. – monarch_dodra Apr 30 '21 at 08:14
3

New versions of Chrome (72+) seem to have eliminated the performance gap. https://measurethat.net/Benchmarks/ListResults/2667

pixelbandito
  • 480
  • 6
  • 12
0

Slice: The Slice method takes 2 arguments 1st Argument: Specifies from where the selection should be started. For Example:

let arr1 = [1,5,8,9];
arr1.slice(1); // [5,8,9]

From the first index (5) it will return the elements.

2nd Argument: Specifies at which level the endpoint should be. If you didn’t put this in the parenthesis while calling the slice method, it will return the elements from the starting index to the end of the array.

  let arr1 = [1,5,8,9];
console.log(arr1.slice(1,3));
    //[ 5, 8 ]

If you put a negative number while calling, the selection will be selected from the end of the array.

let arr1 = [1,5,8,9];
console.log(arr1.slice(-2));
//[ 8, 9 ]

Spread Operator: I can use this Spread Syntax to solve this:

let arr1 = [1,3,6,7];
let arr3 = [5,...arr1,8,9];
console.log(arr3);