In the first example, it is understood that num2
gets the updated value of num1
i.e., 4
.
let num1 = 2;
num1 = 4;
let num2 = num1;
console.log(num1); // result 4
console.log(num2); // result 4
In the second example, why doesn't lastName
get the updated value of ``firstName` i.e, "Henry".
let firstName = "David";
let lastName = firstName;
firstName = "Henry";
console.log(firstName); // result Henry
console.log(lastName); // result David
Is it due to the order of declaration?
CodePudding user response:
It's not the order of declaration, it's the order of assignment.
num2 = num1;
copies the value from num1
to num2
. Now they both contain that same value. There is no ongoing link between them, they just have the same value in them. In your first example, you're looking at the values immediately after assigning to num2
, so of course you see the same thing.
let lastName = firstName;
also copies the value from firstName
to lastName
, and there's also no ongoing link between them, they just contain the same value. But then you change the value in firstName
before looking at them. That just changes the value in firstName
, it has no effect whatsoever on lastName
.
Let's go through your second example step by step:
The declarations are processed upon entry to the scope where the code appears, creating the variables (though not initializing them; if you tried to use them without assigning to them, you'd get an error). That gives us something like this in memory:
firstName: <uninitialized> lastName: <uninitialized>
Now step-by-step code execution starts:
The initializer
firstName = "David"
is executed. Now we have:firstName: "David" lastName: <uninitialized>
The initializer
lastName = firstName
is executed. Now we have:firstName: "David" lastName: "David"
Note that the two variables don't refer to each other in any way. They just have the same value in them.
Now the
firstName = "Henry"
assignment is executed, and we get:firstName: "Henry" lastName: "David"
That assignment has no effect on
lastName
because there is no link between the variables.
Your examples both use primitives (numbers and strings in your case; strings are primitives in JavaScript in the normal case, though in some other languages they're objects [and they can be in JavaScript as well, it's just unusual]). At some point, someone's going to tell you it's different for objects. They're mistaken, it's exactly the same for objects. It's just the value stored in the variables isn't the object, it's a reference to the object saying where it is elsewhere in memory. Think of that reference like a number indexing into a block of memory. That's not exactly true, but it's a good mental model. Let's look at that:
let a = {name: "Henry"};
let b = a;
console.log(a.name); // "Henry"
console.log(b.name); // "Henry"
a = {name: "David"};
console.log(a.name); // "David"
console.log(b.name); // "Henry"
That's exactly the same thing you did with primitives, using objects. Let's walk through it:
The declarations are processed upon entry to the scope:
a: <uninitialized> b: <uninitialized>
Now step-by-step code execution starts:
The initializer
a = {name: "Henry"}
is executed. Now we have:−−−−−−−−−−−−−−− a: Ref45132−−−−−−−−−−−−−−−−−−−>| (object) | b: <uninitialized> −−−−−−−−−−−−−−− | name: "Henry" | −−−−−−−−−−−−−−−
Notice how the value in
a
isn't the actual object, it's something saying where that object is, elsewhere in memory. (I've shown it asRef45132
, but that's just so I have something to show, you can never actually observe the values of references in JavaScript).The initializer
b = a
is executed. Now we have:a: Ref45132−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− | b: Ref45132−−−−−−−−−−−−−−−−−−−−−−−−−− | | | v v −−−−−−−−−−−−−−− | (object) | −−−−−−−−−−−−−−− | name: "Henry" | −−−−−−−−−−−−−−−
The variables don't refer to each other in any way, but they both have the same value in them, and that value says where the object is. So they both indirectly refer to the same object.
The first
console.log(a.name)
andconsole.log(b.name)
are each executed. Since the variables refer to the same object, we get the same name regardless of which variable we use.Henry Henry
Now the
a.name = {name: "David"};
assignment is executed. This changes the value ina
(let's say it changes fromRef45132
toRef91324
), making it refer to a different object, so we have:−−−−−−−−−−−−−−− a: Ref91324−−−−−−−−−−−−−−−−−−−−−−−−−−−−−>| (object) | −−−−−−−−−−−−−−− b: Ref45132−−−−−−−−−−−−−−−−−−−−−−−−−− | name: "David" | | −−−−−−−−−−−−−−− v −−−−−−−−−−−−−−− | (object) | −−−−−−−−−−−−−−− | name: "Henry" | −−−−−−−−−−−−−−−
The second
console.log(a.name)
andconsole.log(b.name)
are each executed. Since the variables refer to different objects, and the objects have different values for theirname
properties, we get different names.David Henry
This next bit is where people get confused and want to say it's different with objects, let's look at doing something different after logging the names the first time:
let a = {name: "Henry"};
let b = a;
console.log(a.name); // "Henry"
console.log(b.name); // "Henry"
a.name = "David"; // <=================== change is here
console.log(a.name); // "David"
console.log(b.name); // "David"
That's very different from the previous example with a = {name: "David"}
(and very different from your examples with primitives) and as you can see the result is different. So what happened? Why did changing a.name
change b.name
? Is there some link between a
and b
? No, there isn't. It's just that they have the same value in them, and that value says where the object is, independent of the variables. Although we're using a
to get to that object, it's not a
we're changing, it's the object we're changing. Since it's the object that changes, we see that change if we get to the object another way (through b
, for instance).
Let's walk through it:
The declarations are processed upon entry to the scope:
a: <uninitialized> b: <uninitialized>
Now step-by-step code execution starts:
The initializer
a = {name: "Henry"}
is executed. Now we have:−−−−−−−−−−−−−−− a: Ref45132−−−−−−−−−−−−−−−−−−−>| (object) | b: <uninitialized> −−−−−−−−−−−−−−− | name: "Henry" | −−−−−−−−−−−−−−−
Notice how the value in
a
isn't the actual object, it's something saying where that object is, elsewhere in memory. (I've shown it asRef45132
, but that's just so I have something to show, you can never actually observe the values of references in JavaScript).The initializer
b = a
is executed. Now we have:a: Ref45132−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− | b: Ref45132−−−−−−−−−−−−−−−−−−−−−−−−−− | | | v v −−−−−−−−−−−−−−− | (object) | −−−−−−−−−−−−−−− | name: "Henry" | −−−−−−−−−−−−−−−
The variables still don't refer to each other in any way, but they both have the same value in them, and that value says where the object is. So they both indirectly refer to the same object.
The first
console.log(a.name)
andconsole.log(b.name)
are each executed. They both refer to the same object, so we get the same name:Henry Henry
Now the
a.name = "David";
assignment is executed. This changes the object, it doesn't changea
.a
is completely unaffected by it, as isb
. But the object they both refer to is updated, as we can see here:a: Ref45132−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− | b: Ref45132−−−−−−−−−−−−−−−−−−−−−−−−−− | | | v v −−−−−−−−−−−−−−− | (object) | −−−−−−−−−−−−−−− | name: "David" | −−−−−−−−−−−−−−−
Since they both refer to the same object, we see the same name:
David David
The distinction is between a = {name: "David"}
and a.name = "David"
. The former creates a new object and updates the value in a
to refer to it. The latter doesn't change a
at all, it just changes the object that a
refers to.
CodePudding user response:
This is variable assignment (you tagged it).
In let lastName = firstName
, lastName
is not any kind of alias to firstName
but takes its value (at the time you execute this instruction) from the other variable firstName
. After that, variables have their own life.