If I have a simple reference to an object as in the first example, the way I understand it is x.a and y.a point to the same address which holds the value 1. When I change the value at that address to 2, the value changes in both x and y.
But in the second example, I use Object.assign to create y. x and y are different references, but x.a and y.a both point to the same address. So why is it that when I change x.a, y.a is not changed in this case?
// simple reference
var x = {a:1};
var y = x;
console.log(x === y); // true
console.log(x.a === y.a) // true
x.a = 2;
console.log(y.a); // 2
console.log('end first example');
// same example but with Oject.assign
var x = {a:1};
var y = Object.assign({}, x);
console.log(x === y); // false
console.log(x.a === y.a); // true, x.a and y.a point to the same address
x.a = 2;
console.log(y.a); // 1, I was expecting this to be 2
Related
Is there any case where
let x = y;
console.log(y !== x) //=> true
So far, no case has worked, neither object nor symbol
?
Oh, I just found out.
Using getters and setters.
If y is a global getter and returns a different value each time, this is possible.
// Defining y.
((i) => {
Object.defineProperty(this, "y", {
get: () => i++
})
})(0)
// y is going to be one more than the previous value it gave,
// but is starts with 1.
// The magical testing...
let x = y;
console.log(x === y); // It returns `false`!
// Even y is not y.
console.log(y === y);
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>
var Bar = function(a, b) {
this.b = b - a;
this.m2 = function() {
return this.a / b;
}
}
var Foo = function(a, b) {
this.a = a;
this.b = b;
Bar.prototype.a = a + b;
Bar.prototype.b = a - b;
Bar.prototype.m1 = Bar.prototype.m2;
Bar.prototype.m2 = function() {
return this.a * a + this.b * b;
}
}
o1 = new Bar(1, 5);
o2 = new Foo(2, 3);
o4 = new Foo(3, 2);
r1 = o1.m1();
console.log(r1)
console.log(o1.a)
console.log(o1.b)
The value of r1 seems to be based off of the prototype methods set forward from the instantiation of the o2 Foo object, and not the the o4 Foo object. However, removing the o4 Foo object seems to stop the entire thing from working. Similarly, removing o2 also prevents it from working.
I feel like correct behavior would be the modification of the object Bar's prototype by o4, meaning the value returned from executing o1.m1() would be derived from the o4 Bar prototype. So,
return this.a * 3 + this.b * 2;
However this is not the case. The correct solution returns from this:
return this.a * 2 + this.b * 3;
This seems quite counterintuitive. What properties are at work here? Why does the solution (that r1 == 22) rely on both the instantiation of o2 and o4?
EDIT: r1 should be 22. I'm trying to figure out what path I need to go down to reach this number.
After the call to new Bar(1, 5), the value of o1.b will be 4. The value of o1.m2 will be that function, but it doesn't matter; that's a red herring.
After the call to new Foo(2, 3):
Bar.prototype.a will be 5
Bar.prototype.b will be -1 (and this will never matter)
Bar.prototype.m1 will be undefined (won't matter)
Bar.prototype.m2 will be a function that's effectively:
function() {
return this.a * 2 + this.b * 3;
}
The a and b (as distinct from this.a and this.b) are "frozen in time" in that function, and they'll never be anything other than 2 and 3.
After the call to new Foo(3, 2):
Bar.prototype.a will be 5
Bar.prototype.b will be 1 (won't matter)
Bar.prototype.m1 will be that "m2" function above
Bar.prototype.m2 will be that same function, except with the local a being 3 and b being 2 (won't matter)
So when o1.m1() is called, we're running a function that's going to be working with the following values:
this.a will be 5, because that's the most recently set value of the Bar prototype property "a"
this.b will be 4, because that's the value of the "b" property on the instance of Bar created in the first step, and instance properties shadow prototype properties
Thus in the function
function() {
return this.a * 2 + this.b * 3;
}
given those values we've got 5 * 2 + 4 * 3 and that's 22.
The question investigates multiple behaviors of JavaScript:
local properties of an object shadow inherited properties, rendering values held in the prototype chain inaccessible,
Closures created by nested functions use outer function variable and parameter values that were in place when the inner function was created: the lexical record chain of nested functions is different for each call to an outer function that creates them (the inner function).
the behavior and value of this inside functions.
var Bar = function(a, b) {
this.b = b - a;
this.m2 = function() {
return this.a / b;
}
}
// every Bar object has a local property b, and method m2
// these are not inherited
// Bar.prototype values for b and m2 will be ignored
var Foo = function(a, b) {
this.a = a;
this.b = b;
Bar.prototype.a = a + b;
Bar.prototype.b = a - b;
Bar.prototype.m1 = Bar.prototype.m2;
Bar.prototype.m2 = function() {
return this.a * a + this.b * b;
}
}
// Foo is (nonsense) code that sets Foo object properties a and b
// These are not used by Bar object methods where "this" refers to the Bar object.
// Setting Bar.prototype.b has no affect as discussed under Bar.
// Although Bar.prototype.m2 is never inherited by Bar objects, it is
// a valid place to store a function value. Initially it is undefined.
// After calling Foo once, Bar.prototype.m1 is undefined.
// After calling Foo twice, Bar.prototype.m1 is
//
// function() { return this.a * a + this.b * b}
//
// Where this.a was calculated in the most recent call to Foo,
// set on Bar.prototype, and inherited by Bar objects,
// this.b is a local property of the Bar object, and
// a and b are the parameter values of the call to Foo which created
// the anonymous function object currently stored in Bar.prototype.m1.
o1 = new Bar(1, 5);
// at this point o1.b is set to 4 and does not change
// o1.a is not in the inheritance chain and is undefined
//
o2 = new Foo(2, 3);
// at this point o1.a is inherited as 5 and o1.m1 is undefined
o4 = new Foo(3, 2);
// at this point o1.a is again inherited as 5 (the sum of 3+2)
// and o1.m1 is defined
r1 = o1.m1();
// uses o1.a=5, o1.b=4 and the values of parameter variables a and b
// held in the closure created by the nested m2 function inside Foo.
//
// the method function is shuffled down before arriving at Bar.prototype.m1,
// where it captures the a and b parameters of the second to last call to Foo,
// which in this example is a=2, b=3
// So the expected value of o1.m1() is
// o1.a * a + o1.b * b
// = 5 * 2 + 4 * 3
// = 22
console.log(r1)
console.log(o1.a)
console.log(o1.b)
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++