Clone Arrays with JavaScript
Believe it or not, there are reasons we use JavaScript frameworks outside of animations and those sexy accordions that people can't do without. The further you get into high-powered JavaScript applications (assuming you're creating true web applications, not websites), the more the need for basic JavaScript functionalities; i.e. JavaScript utilities that have nothing to do with DOM. One of those basic utilities is the ability to clone an array. Quite often I see developers iterating over array items to create their clone; in reality, cloning an array can be as easy as a slice
!
The JavaScript
To clone the contents of a given array, all you need to do is call slice
, providing 0
as the first argument:
var clone = myArray.slice(0);
The code above creates clone of the original array; keep in mind that if objects exist in your array, the references are kept; i.e. the code above does not do a "deep" clone of the array contents. To add clone
as a native method to arrays, you'd do something like this:
Array.prototype.clone = function() { return this.slice(0); };
And there you have it! Don't iterate over arrays to clone them if all you need is a naive clone!
This is a great tip! so worth it!
Interesting tip!
Just to note, I use
.slice()
all the time without passing in ‘zero’ and have never seen an issue. So even though the MDN docs do not say it is optional, it appears to work just fine with no arguments :)If you pass Zero as argument is run faster:
http://jsperf.com/new-array-vs-splice-vs-slice/19
Good reference but the ‘pass zero’ result is only improved (but massively) for one test out of about 20 (Chrome 48.0.2564). It really looks like an anomaly.
It is also much faster, especially for large arrays. Here’s a benchmark I put together:
http://jsperf.com/loop-vs-slice-copy/3
What is the differences between
clonearr=originalarr
andclonearr=originalarr.slice(0)
?Because clonearr=originalarr is an reference for originalarr, so, when you insert a new object or value in array, clonearr is refreshed too.
I don’t understand, why not use clone = myArray?
clone = myArray
makes clone a reference tomyArray
, not a copy of it.Arrays are a specific type of objects. as objects are being passed by reference; meaning that changing source object will change result object and vice versa; you have to clone the result not copy it.
Mesuutt and Jonathan: doing
cloneArr = originalArr
will only copy the pointer of the array and not clone it:thanks @stefan, I understand exactly now :)
There’s a subtle bug that can result from adding something to the prototype of Array. If you iterate over arrays with using
for...in
construct:Note that the for loop will also iterate over the case when i == “clone”!
To be safe, you must iterate by using the length property:
This is because of
construct not the Array prototype.
Take note: if your array is filled with objects, those objects remain linked:
So what if I need to create a clone of an array filled with objects? I cannot have the objects to be by reference in the clone. Iteration my only option?
No one noticed this empties the array in question? That’s not exactly a clone.
It’s really lame you cannot delete or edit comments here.
Use
slice()
notsplice()
.That’s good that you cannot delete your comment! I did the same error and I realized what was going on only by reading your comment… :)
Maybe it’s worth mentioning in a comment, this is very similar to how Python copies lists (arrays)
Adding Array.prototype.clone as mentioned in this article is a terrible idea… as it’s only a shallow clone, and if another developer on your team will use your clone method, they can trip up over this.
Hi, thx for solution, exactly what Iwas looking for
Hi.
I know this post is kinda old, but we were on a discussion about it around here, and we prepared these tests.
http://jsperf.com/array-content-copy/2
many interesting thing around here!
for instance, array.slice is the fastest on google chrome, while in firefox, array.concat was the fastest.
Another interesting thing is the way the browser optimizes the most verbose test, which is not the slowest one!
a handy way to get a deep copy is:
JSON will do the job most of the time but would fail when array contains another json or a function.
you saved me an hour at the least thanks!!
Thanks Sean, that works perfectly!
I added this method, using JSON’s
parse
/stringify
methods to that perf.It works, but this does not have the best of the performances:
http://jsperf.com/array-content-copy/7
don’t make a clone. Is the same of
every change on clone is reflected on myArray. To make a clone you must copy every element singly.
not according to this test
// bad clone
var a = [1,2,3,4,5];
var b = a;
a.push(99);
console.log(a); // [1,2,3,4,5,99]
console.log(b); // [1,2,3,4,5,99]
// good clone
var x = [1,2,3,4,5];
var y = x.slice(0);
x.push(77);
console.log(x); // [1,2,3,4,5,77]
console.log(y); // [1,2,3,4,5]
Yep, that’s not true, Massimo.
try this out
This will only work if your array has simple values in it. If your array contains objects (or other arrays!!!) it will not copy them.
For example
Be careful! here is a function you can use if you know your arrays are nested: http://blog.andrewray.me/how-to-clone-a-nested-array-in-javascript/
Hi Andy.
That’s not entirely the case!
What happens here, is that objects and arrays are passed as reference, and even though, what you were comparing there was their value at [0]!
If you simply run this, you will understand:
By changing a[0], you are NOT altering b[0].
BUT, if you had done this, instead:
This time it changed the array on “b”, but because it was a reference to the same array/object, therefore, any change into one, will be applied to the other.
So, yes, we must be always aware of objects being passed from some place to another, in any case :)
In the example you gave, b is a copy of a, but as a copy, it also copied the pointers/references to the original Array stored on each position.
Man you’re cool! Can I omit ‘0’ in .slice(0)?
slice()
function is working only numeric indexed arrays, not working this array:This version is working with all arrays :
Sean’s code more efficiently:
This clones also object elements in the array
The last time I tested stringify for cloning it was a lot slower than creating objects and copying values over.
More efficiently ? This is so bad in term of performance.
Do not post nonsense on the web David Walsh.
slice()
is not a clone method at all!Slice is a copy method! In other words it copies the values/references from one array to another.
So when you copy objects from array A to B and modify a single item that is referenced in both arrays. Both array A and B will display the new values for this item.
Cloning has a different meaning.
To actually clone objects you must create new objects and copy over values.
“Don’t iterate over arrays to clone them if all you need is a naive clone!”
This is what slice does internally -_- and Erik is true, it’s inappropriate to talk about clone there.
Is there a significant difference between
.slice()
and.slice(0)
? I’ve always used the latter to deep copy. What’s the significance of the first argument being0
? And, it’s not necessary, is it?This
.clone
do the same job of.slice()
without parameters.Also you should never modify objects you don’t “own” (such as standard objects, such as
Array
). It’s a really bad practice.Well this is a great solution … if you do not have complex arrays…
I recommend not to use these solutions because :
There is no built-in function to have a perfect clone of your array, I think we should made a recursive function to clone it perfectly
Now you can do: