1

I am interested in why, in snippet B, y is able to capture the value of x after x has been reassigned when the initialization of y occurs before the reassignment of x.

I have been told the reason is because, in snippet B, x is a reference data-type - it's value is stored external from the variable/identifier and that variable/identifier just points towards the address of the external memory.

However I could still argue that at the specific 'time' when y is being initialized, x is still {5} so y should be {5}. There must be something more for me to understand here - perhaps something to do with the order/timing at which JavaScript assigns value to variables...

A

x = 5;

y = x;

x = 6;

console.log(x);
console.log(y);

B
x = {one: 5};

y = x;

x.one = 6;

console.log(x);
console.log(y);
Sercan
  • 2,081
  • 2
  • 10
  • 23
tonitone110
  • 139
  • 6
  • The first one is assignment of a value, and the second is assignment of a reference. – Mr. Polywhirl Jun 29 '20 at 15:06
  • You are changing the source you are referencing to with `x.one = 6;` – Benjamin Eckardt Jun 29 '20 at 15:06
  • Since you have a reference and javascript is mutable it will produce that, to avoid it you should dreclare y like this y = JSON.parse(JSON.stringify(x)) – Carlos1232 Jun 29 '20 at 15:09
  • @Carlos1232 you could actually apply it as a config to a new object. e.g. `y = {...x}` – Mr. Polywhirl Jun 29 '20 at 15:11
  • Thanks @Mr.Polywhirl. However, second paragraph shows you I'm aware of this. See my third paragraph. – tonitone110 Jun 29 '20 at 15:13
  • @Mr.Polywhirl yes, that's for es6. not all browsers support it. – Carlos1232 Jun 29 '20 at 15:14
  • If you debbug the code It show you y = 5 before you assing x to 6. – Carlos1232 Jun 29 '20 at 15:16
  • @Carlos1232 OK, so use this instead `y = Object.assign({}, x)` instead. You do not need to support IE anymore... even Edge has moved to Chromium and this code works in Edge before they switched anyways. Stop living in the past. – Mr. Polywhirl Jun 29 '20 at 15:17
  • 1
    Does this answer your question? [JavaScript by reference vs. by value](https://stackoverflow.com/questions/6605640/javascript-by-reference-vs-by-value) – sp00m Jun 29 '20 at 15:21
  • Thanks @sp00m. See my third paragraph - my question is really how is JS able to 'go back' to y and continually update it to the new value of `x`. Obviously, JS must initialise variables at the very end when everything's been read, or something... – tonitone110 Jun 29 '20 at 15:27
  • 1
    @tonitone110 There isn't such as "going back to update the other variables": whether you doing `x.one = 6` or `y.one = 6`, you're modifying (aka mutating) the same single _value_, `x` and `y` are just two _references_ pointing to it. – sp00m Jun 29 '20 at 15:31
  • 1
    @sp00m I think I get it now. I confused myself because I was expecting `y` to log out `{one: 5}` but the `console.log(y)` occurs after `x` has mutated the object. If it occurred before the mutation it would've logged out like I expected. However your explanations about references has really solidified the concept for me - so thanks! – tonitone110 Jun 29 '20 at 15:42

3 Answers3

2

Well... tldr; javascript is kinky!

In essence, on your first snippet:

Assign value of, x = 5;
Assign value of, y = x, which holds a reference to the primitive value 5, so y is now directly 5, not x's reference.
Assign value of, x = 6, direct value again, removes the previous correlation with x and y.

The above happens because your assignment is involving primitive types. When you say y=x, you are assigning the primitive 5 to y, not a reference to x, exactly because X holds a primitive, not an object.

On the other hand, your 2nd case involves objects, which are passed by reference instead.

So making changes "here" actually effects all references pointing to "here"

x = {one : 5}
y = x -> This now is an assignment by passing the reference value, i.e Y points to the same object X is pointing.
x.one = 6; -> this will actually effect the same reference Y has

To take it a step further, what if we where to now mutate y again?

If we had, on your 2nd example, this line as the last line

y = { two : 5}

This would not not effect X at all, it would just reassign y with a new completely new object value.

This has to do with how javascript handles references and assignment. Take a look here for a nice starting point of the ref jungle

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
MKougiouris
  • 2,821
  • 1
  • 16
  • 19
  • Thanks @MKougiouris. See my third paragraph - my question is really how is JS able to 'go back' to `y` and continually update it to the new value of `x`? – tonitone110 Jun 29 '20 at 15:21
  • ok, so then for your main question now: Because based on what we said, you are not "re-assigning y OR x" you are just mutating 1 field from X. So y is referencing X, and you can mutate properties from it. But the moment you say y = {some: thing} the "reference" is broken, and y is its own man – MKougiouris Jun 29 '20 at 15:27
  • I think I get it now. I confused myself because I was expecting `y` to log out `{one: 5}` but the `console.log(y)` occurs after `x` has mutated the object. If it occurred before the mutation it would've logged out like I expected. However your explanations about references has really solidified the concept for me - so thanks! – tonitone110 Jun 29 '20 at 15:43
2

In snippet B, y is also a reference. It points exactly to the same place as x does. You have 2 references to the same object.

So after declaring y = x, modifying the value of x.one or y.one is exactly the same thing. enter image description here

dgiugg
  • 1,294
  • 14
  • 23
  • Thanks @dgiugg. I'm aware `y` is also a reference. See my third paragraph - my question is really how is JS able to 'go back' to `y` and continually update it to the new value of `x`? – tonitone110 Jun 29 '20 at 15:23
  • It does not "go back". It is not the "value of `x`". There is one object, independent from `x` and `y`. There are 2 references, `x` and `y`, pointing at that same object. Changing that object by calling it `x` or `y` is strictly equivalent. – dgiugg Jun 29 '20 at 15:28
  • I think I get it now. I confused myself because I was expecting `y` to log out `{one: 5}` but the `console.log(y)` occurs after `x` has mutated the object. If it occurred before the mutation it would've logged out like I expected. However your explanations about references has really solidified the concept for me - so thanks! – tonitone110 Jun 29 '20 at 15:44
1

A nice (truncated) excerpt from https://en.wikipedia.org/wiki/Evaluation_strategy#Call_by_sharing:

If a variable was passed [to a function], it is not possible to simulate an assignment on that variable in the callee's scope. However, since the function has access to the same object as the caller (no copy is made), mutations to those objects within the function are visible to the caller.

sp00m
  • 47,968
  • 31
  • 142
  • 252