Fastest way to duplicate an array in JavaScript - slice vs. 'for' loop

701,075

Solution 1

There are at least 6 (!) ways to clone an array:

  • loop
  • slice
  • Array.from()
  • concat
  • spread operator (FASTEST)
  • map A.map(function(e){return e;});

There has been a huuuge BENCHMARKS thread, providing following information:

  • for blink browsers slice() is the fastest method, concat() is a bit slower, and while loop is 2.4x slower.

  • for other browsers while loop is the fastest method, since those browsers don't have internal optimizations for slice and concat.

This remains true in Jul 2016.

Below are simple scripts that you can copy-paste into your browser's console and run several times to see the picture. They output milliseconds, lower is better.

while loop

n = 1000*1000;
start = + new Date();
a = Array(n); 
b = Array(n); 
i = a.length;
while(i--) b[i] = a[i];
console.log(new Date() - start);

slice

n = 1000*1000;
start = + new Date();
a = Array(n); 
b = a.slice();
console.log(new Date() - start);

Please note that these methods will clone the Array object itself, array contents however are copied by reference and are not deep cloned.

origAr == clonedArr //returns false
origAr[0] == clonedArr[0] //returns true

Solution 2

Technically slice is the fastest way. However, it is even faster if you add the 0 begin index.

myArray.slice(0);

is faster than

myArray.slice();

https://jsben.ch/F0SZ3

Solution 3

what about es6 way?

arr2 = [...arr1];

Solution 4

Easiest way to deep clone Array or Object:

var dup_array = JSON.parse(JSON.stringify(original_array))

Solution 5

var cloned_array = [].concat(target_array);
Share:
701,075
Marco Demaio
Author by

Marco Demaio

Just love coding all day long! Now I'm using PHP and Javascript for my daytime job. I took part in realizing all the back end application to handle the orders, contracts and invoices for a site that sells posta certificata per aziende. Language I love most is C++ Language I hate most is VB6/VB.NET Wishes: to see PHP becoming more OO with operator overloading, and Python add curly braces. I have started coding in BASIC since I was a 13 years old kid with a Commodore 64 and Apple II. During University they taught me C and C++ and JAVA and I realized even more how much I love to code. :) Funny stuff: Micro Roundcube plugin to improve the search box

Updated on February 03, 2022

Comments

  • Marco Demaio
    Marco Demaio over 2 years

    In order to duplicate an array in JavaScript: Which of the following is faster to use?

    Slice method

    var dup_array = original_array.slice();
    

    For loop

    for(var i = 0, len = original_array.length; i < len; ++i)
       dup_array[i] = original_array[i];
    

    I know both ways do only a shallow copy: if original_array contains references to objects, objects won't be cloned, but only the references will be copied, and therefore both arrays will have references to the same objects. But this is not the point of this question.

    I'm asking only about speed.

  • user113716
    user113716 over 13 years
    The primitive types comment applies to the for loop in the question as well.
  • lincolnk
    lincolnk over 13 years
    if I were copying an array of objects, I would expect the new array to reference the same objects rather than cloning the objects.
  • lincolnk
    lincolnk over 13 years
    arguments is not a proper array and he's using call to force slice to run on the collection. results may be misleading.
  • kyndigs
    kyndigs over 13 years
    Yeh I meant to mention that in my post that these stats would probably change now with the broswers improving, but it gives a general idea.
  • Drakarah
    Drakarah over 10 years
    Don't forget the additional cost of the garbage collector if you have to do this very fast a lot. I was copying each neighbour array for each cell in my cellular automata using slice and it was much slower than reusing a previous array and copying the values. Chrome indicated about 40% of the total time was spent garbage collecting.
  • Marco Demaio
    Marco Demaio over 10 years
    well done! This might be the best answer now. Would you be able to explain why the simple test done by lincolnk (it's the above answer stackoverflow.com/a/3978716/260080 ) gives out the opposite result, where slice is the faster than looping? I'm wondering if it's caused by the the type of elements in the array, in his test they were all numbers, in your are a mix of strings and objects.
  • Dan
    Dan over 10 years
    Marco, you are quite right, storing data of one type speeds up an array. Google has written this somewhere, but you can always check it out jsperf.com/new-array-vs-splice-vs-slice/25 yourself However, the biggest difference makes the concrete engine realisation. Algorithms evolve from build to build. On the other hand we can predict evolution when knowing the engine architecture. @lincolnk's benchmarking results look similar to those jsperf.com/new-array-vs-splice-vs-slice/11, October '10 is somewhere close to Chrome 19 and FireFox 10. Oh, slice is shorter to type then concat :)
  • Chris Wesseling
    Chris Wesseling about 10 years
    But is it the fastest?
  • Michael Piefel
    Michael Piefel almost 10 years
    More semantic than splice(), perhaps. But really, apply and this is all but intuitive.
  • Dan
    Dan almost 10 years
    @cept0 no emotions, just benchmarks jsperf.com/new-array-vs-splice-vs-slice/31
  • mate64
    mate64 almost 10 years
    @Dan So what? Your test case results: Firefox 30 nightly is still ~230% faster than Chrome. Check the source code of V8 for splice and you'll be surprised (while...)
  • Seth Holladay
    Seth Holladay over 9 years
    Important note for beginners: because this depends upon JSON, this also inherits its limitations. Among other things, that means your array cannot contain undefined or any functions. Both of those will be converted to null for you during the JSON.stringify process. Other strategies, such as (['cool','array']).slice() will not change them but also do not deep clone objects within the array. So there is a tradeoff.
  • gman
    gman over 9 years
    Sadly for short arrays the answer is vastly different. For example cloning an array of listeners before calling each of them. Those arrays are often small, usually 1 element.
  • Jose Nobile
    Jose Nobile about 9 years
    I tested today 2015-05-04, the fastest method in Chrome 42 for Windows and for Android is .concat()
  • CHAN
    CHAN almost 9 years
    if converted with babel: [].concat(_slice.call(arguments))
  • tremendows
    tremendows over 8 years
    Congrats for benchmarking, demonstrated answer, nice work
  • Yukulélé
    Yukulélé over 8 years
    Very bad perf and don't work with special objects like DOM, date, regexp, function ... or prototyped objects. Don't support cyclic references. You should never use JSON for deep clone.
  • Berkyjay
    Berkyjay about 8 years
    The charts in that benchmarks page show that at least since Chrome 34, the fastest method has been consistently the while loop pre-allocated. It beats all other methods on all browsers by a lot.
  • chrismarx
    chrismarx about 8 years
    shows the slowest performance on chrome- jsperf.com/new-array-vs-splice-vs-slice/113
  • jave.web
    jave.web almost 8 years
    And is myArray.slice(0,myArray.length-1); faster than myArray.slice(0); ?
  • Florian Wendelborn
    Florian Wendelborn almost 8 years
    @diugalde I think the only situation where posting code as a picture is acceptable is when the code is potentially dangerous and should not be copy-pasted. In this case though, it's quite ridiculous.
  • Lukas Liesis
    Lukas Liesis almost 8 years
    worst possible way! Only use if for some issue all other doesn't work. It's slow, it's resources intense and it has all JSON limitations already mentioned in comments. Can't imagine how it got 25 up-votes.
  • basickarl
    basickarl almost 8 years
    jsperf is down. Shitty to refer to it, post the data next time directly here.
  • Drenai
    Drenai almost 8 years
    It deep copies arrays with primitives, and where properties are arrays with further primitives/arrays. For that it is ok.
  • wcochran
    wcochran over 7 years
    You missed this method: A.map(function(e){return e;});
  • Sterling Archer
    Sterling Archer over 7 years
    Not sure where arguments is coming from... I think your babel output is conflating a few different features. It's more likely to be arr2 = [].concat(arr1).
  • Jed Fox
    Jed Fox over 7 years
    Please explain what this does.
  • brandonscript
    brandonscript over 7 years
    While this code snippet may answer the question, it doesn't provide any context to explain how or why. Consider adding a sentence or two to explain your answer.
  • Christopher Swasey
    Christopher Swasey over 7 years
    At least as of 9.1.2 Safari has the slice/concat perf improvements, which are about 20x faster than while.
  • EscapeNetscape
    EscapeNetscape over 7 years
    I hate this kind of comments. It's obvious what it does!
  • Neonit
    Neonit over 7 years
    You're writing about blink browsers. Isn't blink just a layout engine, mainly affecting HTML rendering, and thus unimportant? I thought we'd rather talk about V8, Spidermonkey and friends here. Just a thing that confused me. Enlighten me, if I'm wrong.
  • Oriol
    Oriol over 7 years
    You can use Array.of and ignore the length: Array.of.apply(Array, array)
  • Achim
    Achim over 7 years
    A simple answer for a simple quetions, no big story to read. I like this kind of answers +1
  • tsh
    tsh over 7 years
    @SterlingArcher arr2 = [].conact(arr1) is different from arr2 = [...arr1]. [...arr1] syntax will convert hole to undefined. For example, arr1 = Array(1); arr2 = [...arr1]; arr3 = [].concat(arr1); 0 in arr2 !== 0 in arr3.
  • vsync
    vsync over 7 years
    it's sure easy and very well known solution, but I wonder if it's fast
  • Aloso
    Aloso over 7 years
    In Javascript there aren't two-dimensional arrays. There are just arrays containing arrays. What you are trying to do is a deep copy which is not required in the question.
  • BrunoLM
    BrunoLM over 7 years
    WARNING: .slice, spread, concat, Array.from will not clone object in the array. Use a loop or a deep clone lib
  • TamusJRoyce
    TamusJRoyce over 7 years
    "I'm asking only about speed" - This answer gives no indication on speed. That is the main question being asked. brandonscript has a good point. More information is needed to consider this an answer. But if it were a simpler question, this would be an excellent answer.
  • Harry Stevens
    Harry Stevens almost 7 years
    I tested this in my browser (Chrome 59.0.3071.115) against Dan's answer above. It was more than 10 times slower than .slice(). n = 1000*1000; start = + new Date(); a = Array(n); b = [...a]; console.log(new Date() - start); // 168
  • Harry Stevens
    Harry Stevens almost 7 years
    I tested this in my browser (Chrome 59.0.3071.115) against Dan's answer above. It was nearly 20 times slower than .slice(). n = 1000*1000; start = + new Date(); a = Array(n); var b = JSON.parse(JSON.stringify(a)) console.log(new Date() - start); // 221
  • 4esn0k
    4esn0k over 6 years
    dup.push is wrong in a5, instead dup[i] = should be used
  • stamster
    stamster over 6 years
    Simplest way. JS got this only in 2015... what a crappy language it was before (still far from decent).
  • Marek Marczak
    Marek Marczak over 6 years
    @jave.web you;ve just dropped last element of the array. Full copy is array.slice(0) or array.slice(0, array.length)
  • XT_Nova
    XT_Nova over 6 years
    Probably the only thing that is fast with the spread is to type it. It is waaay less performant than other ways of doing it.
  • Marian07
    Marian07 over 6 years
    Please provide some links about your argument.
  • aleclarson
    aleclarson about 6 years
    You should really link the jsperf. The one you are thinking of is broken, because a new array is created in every test case, except the 'while loop' test.
  • aleclarson
    aleclarson about 6 years
    I made a new jsperf that is more accurate: jsperf.com/clone-array-3
  • Peter Mortensen
    Peter Mortensen over 5 years
    60% what? 60% faster?
  • serv-inc
    serv-inc over 5 years
    @PeterMortensen: 587192 is ~60% (61.1...) of 960589.
  • Neurotransmitter
    Neurotransmitter over 5 years
    Still will not clone something like this: [{a: 'a', b: {c: 'c'}}]. If c's value is changed in the "duplicated" array, it will change in the original array, since it's just a referential copy, not a clone.
  • mesqueeb
    mesqueeb about 5 years
    I tried benchmarking your answer and I got very different results: jsben.ch/o5nLG
  • Lior Elrom
    Lior Elrom about 5 years
    @mesqueeb, the tests might change, depending on ur machine of course. However, feel free to update the answer with your test result. Nice work!
  • Gil Epshtain
    Gil Epshtain about 5 years
    I like your answer a lot, however I try your test and get that arr => arr.slice() is the fastest.
  • Lior Elrom
    Lior Elrom about 5 years
    Thank you for running these tests @GilEpshtain! The result will change, depending on your machine. I noted that above the attached clone function. I think the main takeaway is that some methods are substantially faster than others. Especially when dealing with large data. Is that make sense?
  • Gil Epshtain
    Gil Epshtain about 5 years
    @LiorElrom, your update isn't correct, due to the fact that methods aren't serializable. For example: JSON.parse(JSON.stringify([function(){}])) will output [null]
  • Lior Elrom
    Lior Elrom about 5 years
    Thanks @GilEpshtain, I didn't know that :) I'll make an update
  • Aditya M P
    Aditya M P almost 5 years
    It's a valid thing to point out about how changing cloneNums[0][0] in your example propagated the change to nums[0][0] - but that's because the nums[0][0] is effectively an object whose reference is copied into cloneNums by the spread operator. All that is to say, this behaviour won't affect code where we are copying by value (int, string etc literals).
  • Neil Gaetano Lindberg
    Neil Gaetano Lindberg almost 5 years
    As @TranslucentCloud mentioned, there is still the refernce. I just had a very very confusing time where I was [...baseSet, ...baseSet] to duplicate an array (for a Memory game) and I finally found I had a reference situation. I used lodash's cloneDeep to clone my array of objects. Thought to revisit this post and comment... Next time I'll read all comments first!
  • Admin
    Admin over 4 years
    I run these tests jsperf.com/new-array-vs-splice-vs-slice/152 on Chrome and slice(0) is the fastest one, but I think Array.from() looks cleaner even if it's 22% slower.
  • Wilson Biggs
    Wilson Biggs about 4 years
    It doesn't really matter but as of March 2020, slice (150,936,056 ops/sec ±3.17%) is ~5x faster than the spread operator (34,565,713 ops/sec ±4.69%) in Node.js.
  • edufinn
    edufinn about 4 years
    Nice benchmark. I've tested this on my Mac in 2 browsers: Chrome Version 81.0.4044.113 and Safari Version 13.1 (15609.1.20.111.8) and fastest is spread operation: [...arr] with 4.653076171875ms in Chrome and 8.565ms in Safari. Second fast in Chrome is slice function arr.slice() with 6.162109375ms and in Safari second is [].concat(arr) with 13.018ms.
  • GBMan
    GBMan about 4 years
    Not bad, but unfortunately this doesn't work if you have Object in your array :\ JSON.parse(JSON.stringify(myArray)) works better in this case.
  • Sergio Pisoni
    Sergio Pisoni almost 4 years
    Best way for me is new_array = JSON.parse( JSON.stringify( old_array ) ). In this way all references are killed
  • Donald Duck
    Donald Duck almost 4 years
    I get very different results on different browsers by using the link from @mesqueeb's comment. On Chrome, I get that [...arr] is the fastest followed closely by arr.slice(), on Firefox, I get that arr.slice() is by far the fastest, and on iOS Safari arr.slice() is the fastest followed closely by both [].concat(arr) and [...arr]. So if we look at all these browsers combined, arr.slice() is the fastest. Also, the test results vary from one time to the next even on the same browser, but each time on each browser arr.slice() seems to be not too bad.
  • John Leidegren
    John Leidegren almost 4 years
    This is incorrect, at least on my machine and according to your own benchmarks.
  • nologin
    nologin over 3 years
    You forgot type conversion! See my post below: function clone(arr) { return JSON.parse(JSON.stringify(arr))} ;) ALL other operations do not create clones, because you just change the base adress of the root element, not of the included objects.
  • kschiffer
    kschiffer over 3 years
    The link is dead.
  • f2d
    f2d about 3 years
    jsben.ch/56xWo - sometimes, slice() is faster, sometimes slice(0), both only marginally so (in Firefox 56 and latest Vivaldi, Chrome-based). But slice(0, length) is always noticeably slower (except that it's the fastest in Firefox 87).
  • Will Chen
    Will Chen almost 3 years
    …Why would you do 1000*1000, instead of just typing out 1000000 or doing 1e6?
  • 1nstinct
    1nstinct over 2 years
    It is not cloning. It's still referential copy
  • 1nstinct
    1nstinct over 2 years
    Doing like this is not cloning. It is still referential copy.
  • Stijn de Witt
    Stijn de Witt over 2 years
    It can't be fast, as it has to do a whole lot of serializing and parsing to and from text. If deep copy if the reason you are doing this, better get a good deep-copy lib and just do array.map using the deep copy lib to return a copy of the element
  • Stijn de Witt
    Stijn de Witt over 2 years
    It is cloning the array, but performing a shallow copy of the elements in it. This is however, normal. For deep clones we mostly specifically mention deep cloning. And actually, deep cloning is pretty rare. Because it's more complex than it at first seems to do deep cloning. This answer will work fantastic for primitives though. However, so does var cloned_array = target_array.slice(), which is shorter.
  • JRichardsz
    JRichardsz over 2 years
    You are the only one who noticed the memory location. Extra points for that!!
  • Ben Lesh
    Ben Lesh over 2 years
    Unfortunately, this answer is assuming naive cases where the array only contains values that are the "same shaped" in terms of hidden classes, and therefor result in optimizations. If you have an array of "different shaped" values, the results are definitively different (Array.from) is the fastest in this unoptimized case: jsben.ch/BKvvd
  • Jack Punt
    Jack Punt almost 2 years
    the results for the code [as shown] conflate the time to create the 'a' array with the time to make a copy. more clear timing if you move the a = Array(n) before start =; That aside, b = a.concat() is waaay faster that either