As we move towards the end of this section,
we need to learn about the big difference
between the way primitive types and objects
are stored and memory.
And this is actually a very practical aspect
and one that causes a lot of confusion in beginners.
So let's actually start by writing some code this time
to understand what the confusion actually is,
so that I can then show you
how it all works behind the scenes.
So right now I'm not gonna explain
how the code we will right now works,
but I will just show you what the source of confusion is.
But for now let's start with
a simple example with primitives.
And so remember primitives are like numbers,
strings, Boolean's, et cetera.
So simply setting the age to 30,
and then I'm creating a old age variable.
And this one I will set to the age
because now it is my birthday basically.
And so my age changes to 31,
but I still wanted to preserve my old age here
in this variable.
Okay?
So let's log the results to the console now.
And they should be pretty much what we expect at this point.
So you see that my current age is 31 because, well,
I changed the original one from 30 to 31.
But the old age is still 30 here.
And that's because I set it here at this point of the code
to age, which was still 30 at this point.
And so then changing the age here from 30 to 31
did of course not affect the old age variable again.
Again because at this point here age was still 30.
All right, so here, hopefully there is not much confusion,
everything works just as expected.
But now let's create another scenario which has an object.
So I'm simply going to create an object for me,
with the name of Jonas and age 30.
And now let's copy this object
because let's say that I have a friend
who's also called Jonas.
And so instead of creating a brand new object from scratch,
I would just copy the me object.
So const Friend equals Me.
Okay?
And so now both the name and the age are the same,
but let's say that we have different ages.
And so let's change the age of my friend
and that's pretty straightforward, right?
So let's say that he is 27 years old.
But of course we did not change me.age, right?
So let's now take a look at both of them in the console.
So first my friend,
so that's the Friend object and then also Me,
or we could say Jonas, it doesn't really matter.
But what matters is that we will see the Me object
and what do we think will happen now?
So let me show it to you.
And now we get that both me and my friend
have the age of 27.
And that looks a little bit strange because all we did
was to change the age of the friend, right?
Nowhere here, I have me.age equals 27,
but still for myself, so here at the Me object,
the age is also 27.
And so that is what I mean by source of confusion.
And so in this video,
let's now find out why it works this way.
Now, before we can understand the code that we just wrote,
we need to review some basics here.
First, we need to remember about
JavaScripts primitive data types,
which are number, string, Boolean, undefined, null, symbol,
and BigInt.
Then everything else are basically objects.
So objects created with the object literal, arrays
and even functions are all objects.
Now, when we're talking about memory and memory management,
it's usual to call primitives, primitive types
and objects reference types because of the different way
in which they are stored in memory.
Next, we need to remember about the JavaScript engine.
So the engine has two components, the call stack,
where functions are executed and to heap where objects
are stored in memory.
And that's right, all of objects,
or in other words, reference types
will get stored right in the memory heap.
And I mentioned that when we first talked about the engine,
but now you will finally learn how that actually works.
On the other hand, primitives or primitive types
are stored in the call stack.
And with that, I mean that primitive types
are stored in the execution contexts
in which they are declared.
But for the sake of simplicity,
let's ignore that detail now.
And simply say that primitive types
are stored in a call stack
because that's where execution context run.
All right, but now how does all that actually work?
And why did our code example earlier behave
in that weird way?
Well, let's find out.
So here we have the two code examples from earlier,
as well as the engine with call stack and heap.
And let's start by looking at the primitive values example.
So when we declare a variable like age equals 30,
what actually happens inside the JavaScript engine
and the computer's memory?
Well, first JavaScript will create
a so-called unique identifier with the variable name.
Then a piece of memory will be allocated
with a certain address, so 0001 in this example,
and finally the value would be stored in memory
at the specified address.
So in this case, the value 30
will be specified at memory address 0001.
And remember this all happens in a call stack
where primitive values are stored.
Now what's extremely important to understand here
is that the identifier actually points to the address
and not to the value itself.
So we would say that the age variable is equal to 30,
but in fact, age is equal to the memory address 0001,
which holds the value of 30, all right?
And this subtle distinction
is very important to keep in mind.
Now, in the next line, we declare old age
to be equal to age.
So knowing that a variable actually holds a memory address,
what should old age look like?
Well, it will simply point to the same memory address
as the age variable.
And so it will look like old age, is simply 30 as well.
Great, but now in the next line, we set eight to 31.
So what will happen then?
The value at address 0001
will certainly not become 31
because that would change old age as well,
since they both point to the same address.
So that would make no sense at all.
Also the value at a certain memory address is immutable,
or in other words, it cannot be changed.
So instead what's going to happen here
is that a new piece of memory is allocated.
So it's created and the age identifier now simply points
to the new address, which is holding the new value of 31,
all right?
And that's why when we lock both
or variables to the console in the end,
they both return exactly values that we expect.
Now with reference values, things work a bit differently,
which is the reason why this example gave us
that unexpected, weird behavior earlier in practice.
So what's the origin of this weird unexpected result?
Well, when a new object is created such as this Me object,
it is stored in the heap.
And such as before there is a memory address
and then the value itself.
Now in the case of reference values
like this Me object the Me identifier
does actually not point directly
to this newly created memory address in the heap.
So in this example, D30F,
instead, it will point to a new piece of memory
that's created in the stack.
And this new piece of memory will then point to the object
that's in the heap by using the memory address as its value.
In other words, the piece of memory in the call stack
has a reference to the piece of memory in the heap,
which holds or Me object, okay?
And that's the reason why we call objects reference types
in this context.
So again, when we declare a variable as an object,
an identifier is created,
which points to a piece of memory in the stack,
which in turn points to a piece of memory in the heap.
And that is where the object is actually stored.
And it works this way because objects might be
too large to be stored in the stack.
Instead they are stored in the heap,
which is like an almost unlimited memory pool.
And the stack just keeps a reference
to where the object is actually stored in the heap
so that it can find it whenever necessary.
Now, moving on in the code,
we create a new variable called Friend
that we set equal to the Me object.
So what will happen here?
Well, just like with primitive values,
the Friend identifier will point
to the exact same memory address as the Me identifier.
And again, that address contains the reference,
which then points to the object itself.
And like this the Friend object is now essentially
the exact same as the Me object.
Do you see that here in the diagram?
So here comes the interesting part
because now we're actually gonna change a property
in the Friend object by setting friend.age to 27.
So what happens then is that the object
is found in the heap, and the 30 is changed to 27.
Great.
And by the way, even though we defined the Friend variable
as a constant, we can actually still manipulate the object
without problems.
And when we think about that, it makes sense
because we're actually not changing the value in memory
for the Friend identifier, it is still D30F.
So the reference to the object.
All we did was to change the value in the heap,
and that's not a problem.
So it's a misconception that all variables declared
with const are immutable.
In fact, that is only true for primitive values,
but not for reference values.
So keep that in mind, whenever you're working with const.
Anyway, as we lock the Friend variable to the console,
we get the age of 27, just as we said it before.
But then when we lock the Me object,
we get that weird behavior
that we could previously not explain and not understand.
But with everything that we learned in this lecture,
it actually now makes sense
that in the Me object, age is now also 27,
even though we never changed me.age directly.
And the reason for this, as we can see in this slide
is the fact that Me and Friend
actually point to the exact same object in the memory heap.
So whenever we change something in this object,
it will always be reflected in Friend and in Me.
So in both these objects.
So these are basically just two different identifiers
pointing to the exact same value.
And once again, that value is the memory address D30F
which points to the reference in the memory heap.
And one important implication of this
is that whenever you think that you're copying an object,
you're really just creating a new variable
that points to the exact same object.
And this has huge implications
for the way JavaScript works in practice.
And we will see that in the next video
and throughout the course.
Now there are actually ways around this,
as we will also learn later.
but in general, this is how reference values work
in JavaScript.
So make sure to really understand this,
as well as the implications that this behavior has,
even if that means that you have to re-watch this lecture
or at least the explanation of this slide, all right?
Then once you really understand what happened here,
in this example, let's understand primitive values
and reference values even better in practice
in the next lecture.
But before we do that, let me just quickly take a second
and mention a three more, really big topics
about how JavaScript works behind the scenes
that will not be in the section,
but closer to where we actually need to learn about them.
For example, one fundamental concept of JavaScript
is prototypal inheritance.
But we will only talk about that
in the object oriented programming section of this course.
Because it doesn't make sense to learn about this now
only to then forget it all
until we finally reach that section.
The same is true for a detailed lecture on the event loop.
So I already introduced the event loop in this section,
but in the section about asynchronous JavaScript,
we will dive really deep into
how exactly the event loop works
and why it's such a fundamental piece
of the JavaScript engine.
Finally, we will have lectures on
how the DOM actually works behind the scenes too.
And that's going to be
in the advanced DOM and events section
so that you can then apply
what you learned there right away.
Okay?
And with that being said, let's now move on.