I've written the following JavaScript:
var myArray = ['a', 'b', 'c'];
var copyOfMyArray = myArray;
copyOfMyArray.splice(0, 1);
alert(myArray); // alerts ['b','c']
alert(copyOfMyArray); // alerts ['b','c']
var myNumber = 5;
var copyOfMyNumber = myNumber;
copyOfMyNumber = copyOfMyNumber - 1;
alert(myNumber); // alerts 5
alert(copyOfMyNumber); // alerts 4
This code declares a variable myArray
and sets it to an array value. It then declares a second variable copyOfMyArray
and sets it to myArray
.
It performs an operation on copyOfMyArray
and then alerts both myArray
and copyOfMyArray
. Somehow, when I perform an operation on copyOfMyArray
, it appears that the same operation is performed on myArray
.
The code then does the same thing with a number value: It declares a variable myNumber
and sets it to a number value. It then declares a second variable copyOfMyNumber
and sets it to myNumber
. It performs an operation on copyOfMyNumber
and then alerts both myNumber
and copyOfMyNumber
. Here, I get the expected behavior: different values for myNumber
and copyOfMyNumber
.
What is the difference between an array and a number in JavaScript that it seems changing an array changes the value of a copy of the array, where as changing a number does not change the value of a copy of the number?
I'm guessing that for some reason, the array is referred to by reference and the number by value, but why? How can I know what behavior to expect with other objects?
I find this the easiest way to make a deep clone of an object or array:
By stringifying it we make a copy of it which is immutable which we can then convert back into JSON.
https://codepen.io/Buts/pen/zWdVyv
An array in JavaScript is also an object and variables only hold a reference to an object, not the object itself. Thus both variables have a reference to the same object.
Your comparison with the number example is not correct btw. You assign a new value to
copyOfMyNumber
. If you assign a new value tocopyOfMyArray
it will not changemyArray
either.You can create a copy of an array using
slice
[docs]:But note that this only returns a shallow copy, i.e. objects inside the array will not be cloned.
So everyone here has done a great job of explaining why this is happening - I just wanted to drop a line and let you know how I was able to fix this - pretty easily:
This is using the ... spread syntax.
Spread Syntax Source
EDIT: As to the why of this, and to answer your question:
The answer is that in JavaScript, arrays and objects are mutable, while strings and numbers and other primitives are immutable. When we do an assignment like:
copyOfMyArray is really just a reference to myArray, not an actual copy.
I would recommend this article, What are immutable and mutable data structures?, to dig deeper into the subject.
MDN Glossary: Mutable
You don't have any copies.
You have multiple variables holding the same array.
Similarly, you have multiple variables holding the same number.
When you write
copyOfMyNumber = ...
, you're putting a new number into the variable.That's like writing
copyOfMyArray = ...
.When you write
copyOfMyArray.splice
, you're modifying the original array.That isn't possible with numbers because numbers are immutable and cannot be modified,
Cloning objects -
A
loop / array.push
produces a similar result toarray.slice(0)
orarray.clone()
. Values are all passed by reference, but since most primitive data types are immutable, subsequent operations produce the desired result - a 'clone'. This is not true of objects and arrays, of course, which allow for modification of the original reference (they are mutable types).Take the following example:
The operations run on the newArray indices all produce the desired result, except the final (object), which, because it is copied by reference, will mutate the originalArray[3] as well.
https://jsfiddle.net/7ajz2m6w/
Note that
array.slice(0)
and array.clone()
suffers from this same limitation.One way to solve this is by effectively cloning the object during the push sequence:
https://jsfiddle.net/e5hmnjp0/
cheers
An array, or an object in javascript always holds the same reference unless you clone or copy. Here is an exmaple:
http://plnkr.co/edit/Bqvsiddke27w9nLwYhcl?p=preview
For object clone, we can use .clone() in jquery and angular.copy(), these functions will create new object with other reference. If you know more functions to do that, please tell me, thanks!