This question already has answers here:
Modifying a copy of a JavaScript object is causing the original object to change
(13 answers)
Closed 3 years ago.
Can anyone explain to me why the output value is changed to "20, 2" instead of the original "1, 2"?
<!DOCTYPE html>
<html>
<body>
<p id="demo"></p>
<p id="demo1"></p>
<script>
var x = {
a: 1,
b: 2
};
var y = x;
y.a = 20;
document.getElementById("demo").innerHTML = x.a;
document.getElementById("demo1").innerHTML = x.b;
</script>
</body>
</html>
You are pointing y to the reference of x which itself is pointing to the object {a:1,b:2}.
So in memory it is:
x --> {a:1,b:2}
After you do y = x, it becomes:
y --> x --> {a:1,b:2}
Or to put it simply:
x --> {a:20,b:2}
^
|
y -------
Now when you do y.a = 20, since y and x are both pointing to the same object when properties of the object is changed through either of the references x or y the change will be reflected in both the references:
y --> {a:20,b:2}
^
|
x -------
That is why you get 20,2 when you get x.a.
var y=x
In the above line y is passed the reference of x instead of the whole object x. Any changes made to the object will get reflected in all the variables containing the reference of the object.
Because its the same reference (same address for memory location where the object is stored) both x and y are now the same reference so changing one will change the value stored, and now as they are the same reference they will output the same object values.
I would add something extra to make this answer more productive.
Shallow -Copy
Shallow copy is a bit-wise copy of an object. A new object is created
that has an exact copy of the values in the original object. If any of
the fields of the object are references to other objects, just the
reference addresses are copied i.e., only the memory address is
copied.
example
let x={"a":1,"b":2};
let y=x; //It makes a copy of the reference to x into y
So, the addresses of x and y will be the same i.e. they will be pointing to the same memory location.
so if you do this
y.a=9;
and now when you print y on the screen
console.log(y) // it prints {"a":9,"b":2};
but the interesting fact here is , when you print x
console.log(x) // it also prints {"a":9,"b":2};
So Now how to change this scenario??. The solution is a deep copy
Deep copy
A deep copy copies all fields and makes copies of dynamically
allocated memory pointed to by the fields. A deep copy occurs when an
object is copied along with the objects to which it refers.
in Lehman terms you create a variable y allocate it a different memory location, copy all the members of x, assign the copied members to y
the easiest way to do it is by stringifying the object
let y=JSON.parse(JSON.stringify(x))
now if we do
y.a=9
and print y
console.log(y) // it prints {"a":9,"b":2};
and if we print x
console.log(x) // it prints {"a":1,"b":2};
/// shallow copy
let x = {
"a": 1,
"b": 2
};
let y = x;
y.a = 9;
console.log(y);
console.log(x);
// Deep Copy
let z = {
"a": 1,
"b": 2
};
let t = JSON.parse(JSON.stringify(z));
t.a = 9;
console.log("z:", z);
console.log("t:", t);
This scenario becomes more fun when we have nested objects
let c = {
"a": {
"A": 1
},
"b": {
"B": 2
}
};
let t = Object.assign({}, c); // It is also shallow copying
t.a.A = "7"; // since a is a nested object so again reference is passed
console.log(c);
console.log(t)
console.log("Second Scenario-------------------")
let d = {
"a": {
"A": 1
},
"b": {
"B": 2
}
};
let k = JSON.parse(JSON.stringify(d));
k.a.A = 88
console.log(d)
console.log(k)
That is because y & x both point to same memory location.If you want a separate copy , then deep copy the object. JSON.parse & JSON.stringify
var x = {
a: 1,
b: 2
};
var y = JSON.parse(JSON.stringify(x));
y.a = 20;
document.getElementById("demo").innerHTML = x.a;
document.getElementById("demo1").innerHTML = x.b;
<p id="demo"></p>
<p id="demo1"></p>
Related
I have a variable pointing to an object and would like to replace that object with another modified one. Is there any Javascript function that can do what my hypothetical "assign" function does in the example console session below?
var x = [[1,2,3], [4,[8,2,[1,4,"Delete Me"],4],6]]
var y = getSubArrayWithString(x) // Equivalent to y = x[1][1][2] in this case
JSON.stringify(y)
>>> "[1,4,"Delete Me"]"
var newY = y.filter(item => item !== "Delete Me")
y.assign(newY) // Equivalent to x[1][1][2] = newY
JSON.stringify(x)
>>> "[[1,2,3],[4,[8,2,[1,4],4],6]]"
If I do y = newY that just reassigns the y variable to point at the newY object, it doesn't modify x.
I know I could modify y in place using splice, but that won't work when I'm applying more complex changes to get newY
Ideally getSubArrayWithString() would return a reference to the parent of the array you are interested in modifying (and maybe even the index you want). Then it's easy:
var x = [[1,2,3], [4,[8,2,[1,4,"Delete Me"],4],6]]
var [y, ind] = [x[1][1], 2] // getSubArrayWithString returns parent and index
y[ind] = y[ind].filter(item => item !== "Delete Me")
console.log(x)
If your really stuck with just the array reference, you can use splice() to alter the array rather than overwrite it. You could even splice() everything and reassign the new values, but this seems pretty inefficient:
var x = [[1,2,3], [4,[8,2,[1,4,"Delete Me"],4],6]]
var y = x[1][1][2]
var newY = y.filter(item => item !== "Delete Me")
y.splice(0,y.length) // sketchy, but works
Object.assign(y, newY)
console.log(x)
This question already has answers here:
Is JavaScript a pass-by-reference or pass-by-value language?
(33 answers)
JavaScript by reference vs. by value [duplicate]
(4 answers)
Closed 5 years ago.
As I understand, object references x in x = { greet: hi } stores a reference to object { greet:hi} unlike primitive types that hold actual values ( y=10)
In the following code, console.log(y) outputs {greet: "hi"}.
Why does y object reference is not updated to point to {greet: 'hello'} when x obj ref is updated to point to x = {greet: 'hello'}
var x = {greet: 'hi'};
var y = x;
x = {greet: 'hello'};
console.log(y);
console.log(x)
Because in line x = {greet: 'hello'}; a new object is being created.
Use x.greet = 'hello'; to update old object.
var x = {greet: 'hi'};
var y = x;
x.greet = 'hello';
document.getElementById("text_show").innerHTML= x.greet + " | " + y.greet;
<div id="text_show"></div>
See here to know about objects in JavaScript
Why does y object reference is not updated to point to {greet:
'hello'} when x obj ref is updated to point to x = {greet: 'hello'}
Because you have assigned a new reference to x while y is still pointing to original one.
When you say
var y = x;
you are pointing y to the same reference that x was pointing to, you are not pointing y to x.
I have a function that generates numbers within a range.
I created a composite type like this:
var cowPosition = {
x: 0,
y: 0
};
I also created an array:
var positionsArray = [];
then, I proceed to iterate to fill the array with the composite type.
All of this is inside a function which returns the array.
Here's the function:
function generateCowPositions(numberOfCows){
var positionsArray = [];
var cowPosition = {
x: 0,
y: 0
};
var x,y;
for (var i = 0; i < numberOfCows; i++) {
x = randomPosition(0,5);
y = randomPosition(0,5);
x = x * 80;
y = y * 80;
cowPosition.x = x;
cowPosition.y = y;
positionsArray[i] = cowPosition;
}
return positionsArray;
}
When I run it, it fills the whole array with the last two generated coordinates.
There is no "composite type" in JavaScript. What you are referring to is called an object.
The problem you are having is that objects are passed by reference, not by value. This means that if you store an object into a variable called a and modify it in some function, the value stored in a will be modified too.
What you need to do is:
function generateCowPositions(numberOfCows) {
var positionsArray = [];
// note: cowPosition object is not needed anymore, so I've removed it
var x, y;
for (var i = 0; i < cantidadVacas; i++) {
x = randomPosition(0, 5);
y = randomPosition(0, 5);
x = x * 80;
y = y * 80;
// create a new object in every intration
positionsArray[i] = {
x: x,
y: y,
};
}
return positionsArray;
}
Because there is only one instance of cowPosition in your code. So every iteration of your loop simply changes that one object, and at the end of the loop you simple keep the result of the last iteration.
Each index in the array is pointing to the exact same object, being cowPosition
I'm not sure what you are trying to accomplish 100%, but you should create a new object at each iteration. There isn't a need to initialize x and y in the object.
Simply:
function generateCowPositions(numberOfCows){
var positionsArray = [];
var cowPosition = {}
var x,y;
for (var i = 0; i < cantidadVacas; i++) {
x = randomPosition(0,5);
y = randomPosition(0,5);
x = x * 80;
y = y * 80;
cowPosition.x = x;
cowPosition.y = y;
positionsArray[i]= Object.assign({}, cowPosition);
}
return positionsArray;
}
JavaScript is an object-oriented language where objects are passed by-reference, not by-value. I suspect you're thinking of C and C++ where struct/class values are by default copied in their entirety by the = operator. In JavaScript it's closer to C# and Java where object / non-primitive types have their references copied instead.
Objects in javascript are passed as references.
positionsArray[i] = cowPosition; sets positionsArray[i] to a reference to the cowPosition object.
After the loop, all array elements reference the same cowPosition object. Therefore, since each loop of the array changes the underlying cowPosition object, all the array elements appear to have the same x and y position.
A simple solution to this problem would be to shallow copy the cowPosition object inside the loop, such that each array element references a difference position object and changing the underlying cowPosition object has no effect on the shallow copies inside the positionsArray, like so:
positionsArray[i] = JSON.parse(JSON.stringify(cowPosition));
This works by converting the object to a string and back again using javascript's native JSON implementation.
i have a javascript code fragment as
var u = {};
var x = y = z = {"cvalue":"cell", "call":function(){alert(this.cvalue);}};
(function(){u=x;/*change all cvalue in x,y, z, u*/ u.cvalue = "notcell";})();
if(u == x && x == y && y == z && z == u){
u.call();
}
//only u goes to null
u = null;
//x,y,z stay same
alert(x.cvalue);
wondering why u = null only applies for u?
Variables don't actually hold an object, but simply hold a reference to one. By assigning u to null, you're dropping the reference that u had to the object.
A more basic example:
var x = { 'name': 'Bob' };
var y = x;
console.log(x); // Object { name="Bob"}
console.log(y); // Object { name="Bob"}
y.name = 'Jack';
console.log(x); // Object { name="Jack"}
console.log(y); // Object { name="Jack"}
x = null;
console.log(x); // null
console.log(y); // Object { name="Jack"}
Note how our object isn't held in x. It's held somewhere in memory, and x is referring to it. When we do y = x, we copy the reference to y, and therefore y begins to refer to the same object. Setting x to null simply drops the reference that x holds to the object, leaving the actual object unaffected. If we were to set y to null, or to anything else, the garbage collector would eventually pick up the object for destruction.
Daniel is right, but you have to be careful because in Javascript you are sometimes dealing with a copy, and othertimes dealing with the original. For example...
var a = new Object();
a.foo = new function(){alert("I exist")};
var b = a;
b.foo = null;//this erases the function from both a and b (technically, there is only one since a and b point to the same place in memory).
a.foo();//this now fails since there is no longer a function called foo
b = null;//this does NOT affect a in any way as per Daneiel Vassallo's explanation.
You are assigning the exact same object to x, y and z, not a copy of it's value, but the exact same object.
In pseudo code:
var u = OBJECT_A // u points to OBJECT_A
var x = y = z = OBJECT_B // x y and z points to OBJECT_B
(function(){
u=x; // Drop reference to OBJECT_A and point to OBJECT_B
/*change all cvalue in x,y, z, u*/
u.cvalue = "notcell"; //Changes the cvalue in OBJECT_B
// Remember x,y,z, and u points to OBJECT B
// so x.cvalue, y.cvalue, z.cvalue and u.cvalue is the same
})();
if(u == x && x == y && y == z && z == u){
u.call();
}
//only u goes to null
u = null; // Drop reference to OBJECT_B and point to NULL.
//x,y,z still points to OBJECT_B
alert(x.cvalue);
I have the following simple script.
<script>
SPC = {
a : [10],
b : 10,
t: function()
{
y = this.a;
z = this.b;
y[0]++;
z++;
alert('this.a[0] = ' + this.a[0] + '\nthis.b = ' + this.b)
}
}
SPC.t();
SPC.t();
</script>
Running it in your browser will display two alert boxes with:
this.a[0] = 11
this.b = 10
and
this.a[0] = 12
this.b = 10
The question is, why does the value of this.a[0] increment? I'm assigning "y = this.a" and updating element of "y" as "y[0]++;"?
At the same time, exactly the same thing is happening with "b": "z = this.b; z++". Yet, "this.b" remains equal to 10.
How can I change value of "y[0]" in the local scope without affecting "this.a"?
Any ideas?
Thanks!
a is an array, and you're simply copying a reference to the array into y. You need to copy the array a's contents into a new array y instead (using Array.slice() (y = a.slice() in your case) is the easiest way).
(Or, if you only need a[0], you can set y = a[0]. Subsequent changes to y will not affect a[0], since you are copying the value.)
See the "Javascript Arrays Are Assigned By Reference" and "Passing Arrays As Values" sections of this article for more information.
Try Array.slice() function.
y = this.a.slice()
This will create a copy of a array and assign it to y. So modification of y won't affect a.
you are assigning the address value of array a and b into y and z.
therefore, y, and z become the exact copy of a and b.
instead of assigning address value into y and z.
you just need to take content value of a and b and assign them into y and z
y = a[0]
z = b[0]
and then y++