Fastest way to duplicate an array in JavaScript - slice vs. 'for' loop
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, andwhile loop
is 2.4x slower. -
for other browsers
while loop
is the fastest method, since those browsers don't have internal optimizations forslice
andconcat
.
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();
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);
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, 2022Comments
-
Marco Demaio over 2 years
In order to duplicate an array in JavaScript: Which of the following is faster to use?
Slice
methodvar dup_array = original_array.slice();
For
loopfor(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 over 13 yearsThe primitive types comment applies to the
for
loop in the question as well. -
lincolnk over 13 yearsif I were copying an array of objects, I would expect the new array to reference the same objects rather than cloning the objects.
-
lincolnk over 13 years
arguments
is not a proper array and he's usingcall
to forceslice
to run on the collection. results may be misleading. -
kyndigs over 13 yearsYeh 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 over 10 yearsDon'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 over 10 yearswell 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 over 10 yearsMarco, 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 about 10 yearsBut is it the fastest?
-
Michael Piefel almost 10 yearsMore semantic than
splice()
, perhaps. But really, apply and this is all but intuitive. -
Dan almost 10 years@cept0 no emotions, just benchmarks jsperf.com/new-array-vs-splice-vs-slice/31
-
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 over 9 yearsImportant note for beginners: because this depends upon JSON, this also inherits its limitations. Among other things, that means your array cannot contain
undefined
or anyfunction
s. Both of those will be converted tonull
for you during theJSON.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 over 9 yearsSadly 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 about 9 yearsI tested today 2015-05-04, the fastest method in Chrome 42 for Windows and for Android is .concat()
-
CHAN almost 9 yearsif converted with babel:
[].concat(_slice.call(arguments))
-
tremendows over 8 yearsCongrats for benchmarking, demonstrated answer, nice work
-
Yukulélé over 8 yearsVery 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 about 8 yearsThe 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 about 8 yearsshows the slowest performance on chrome- jsperf.com/new-array-vs-splice-vs-slice/113
-
jave.web almost 8 yearsAnd is
myArray.slice(0,myArray.length-1);
faster thanmyArray.slice(0);
? -
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 almost 8 yearsworst 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 almost 8 yearsjsperf is down. Shitty to refer to it, post the data next time directly here.
-
Drenai almost 8 yearsIt deep copies arrays with primitives, and where properties are arrays with further primitives/arrays. For that it is ok.
-
wcochran over 7 yearsYou missed this method:
A.map(function(e){return e;});
-
Sterling Archer over 7 yearsNot sure where
arguments
is coming from... I think your babel output is conflating a few different features. It's more likely to bearr2 = [].concat(arr1)
. -
Jed Fox over 7 yearsPlease explain what this does.
-
brandonscript over 7 yearsWhile 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 over 7 yearsAt least as of 9.1.2 Safari has the slice/concat perf improvements, which are about 20x faster than while.
-
EscapeNetscape over 7 yearsI hate this kind of comments. It's obvious what it does!
-
Neonit over 7 yearsYou'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 over 7 yearsYou can use
Array.of
and ignore the length:Array.of.apply(Array, array)
-
Achim over 7 yearsA simple answer for a simple quetions, no big story to read. I like this kind of answers +1
-
tsh over 7 years@SterlingArcher
arr2 = [].conact(arr1)
is different fromarr2 = [...arr1]
.[...arr1]
syntax will convert hole toundefined
. For example,arr1 = Array(1); arr2 = [...arr1]; arr3 = [].concat(arr1); 0 in arr2 !== 0 in arr3
. -
vsync over 7 yearsit's sure easy and very well known solution, but I wonder if it's fast
-
Aloso over 7 yearsIn 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 over 7 yearsWARNING:
.slice
,spread
,concat
,Array.from
will not clone object in the array. Use a loop or a deep clone lib -
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 almost 7 yearsI 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 almost 7 yearsI 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 over 6 years
dup.push
is wrong ina5
, insteaddup[i] =
should be used -
stamster over 6 yearsSimplest way. JS got this only in 2015... what a crappy language it was before (still far from decent).
-
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 over 6 yearsProbably 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 over 6 yearsPlease provide some links about your argument.
-
aleclarson about 6 yearsYou 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 about 6 yearsI made a new jsperf that is more accurate: jsperf.com/clone-array-3
-
Peter Mortensen over 5 years60% what? 60% faster?
-
serv-inc over 5 years@PeterMortensen: 587192 is ~60% (61.1...) of 960589.
-
Neurotransmitter over 5 yearsStill will not clone something like this:
[{a: 'a', b: {c: 'c'}}]
. Ifc
'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 about 5 yearsI tried benchmarking your answer and I got very different results: jsben.ch/o5nLG
-
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 about 5 yearsI like your answer a lot, however I try your test and get that
arr => arr.slice()
is the fastest. -
Lior Elrom about 5 yearsThank 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 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 about 5 yearsThanks @GilEpshtain, I didn't know that :) I'll make an update
-
Aditya M P almost 5 yearsIt's a valid thing to point out about how changing
cloneNums[0][0]
in your example propagated the change tonums[0][0]
- but that's because thenums[0][0]
is effectively an object whose reference is copied intocloneNums
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 almost 5 yearsAs @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 over 4 yearsI run these tests jsperf.com/new-array-vs-splice-vs-slice/152 on Chrome and
slice(0)
is the fastest one, but I thinkArray.from()
looks cleaner even if it's 22% slower. -
Wilson Biggs about 4 yearsIt 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 about 4 yearsNice 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]
with4.653076171875ms
in Chrome and8.565ms
in Safari. Second fast in Chrome is slice functionarr.slice()
with6.162109375ms
and in Safari second is[].concat(arr)
with13.018ms
. -
GBMan about 4 yearsNot 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 almost 4 yearsBest way for me is new_array = JSON.parse( JSON.stringify( old_array ) ). In this way all references are killed
-
Donald Duck almost 4 yearsI 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 byarr.slice()
, on Firefox, I get thatarr.slice()
is by far the fastest, and on iOS Safariarr.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 browserarr.slice()
seems to be not too bad. -
John Leidegren almost 4 yearsThis is incorrect, at least on my machine and according to your own benchmarks.
-
nologin over 3 yearsYou 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 over 3 yearsThe link is dead.
-
f2d about 3 yearsjsben.ch/56xWo - sometimes,
slice()
is faster, sometimesslice(0)
, both only marginally so (in Firefox 56 and latest Vivaldi, Chrome-based). Butslice(0, length)
is always noticeably slower (except that it's the fastest in Firefox 87). -
Will Chen almost 3 years…Why would you do
1000*1000
, instead of just typing out1000000
or doing1e6
? -
1nstinct over 2 yearsIt is not cloning. It's still referential copy
-
1nstinct over 2 yearsDoing like this is not cloning. It is still referential copy.
-
Stijn de Witt over 2 yearsIt 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 over 2 yearsIt 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 over 2 yearsYou are the only one who noticed the memory location. Extra points for that!!
-
Ben Lesh over 2 yearsUnfortunately, 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 almost 2 yearsthe 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