Jonas: Let's now create a similar example
to the one that we had in the last video
so that we can explore this idea of object references
that we just learned about in the previous lecture,
but now by writing some code.
So let's start this lecture simply
by just writing an object.
I'm gonna call this object jessica,
because it will contain some information about this person,
so this Jessica.
So the first name is indeed Jessica.
Then the last name is Williams.
And I believe we have used actually this person before.
And let's say the age is 27.
Now, as we already know,
this object will now be stored in the heap
inside the JavaScript engine of our browser right here.
So this case, this browser that I'm running this code in.
And then the call stack will hold a reference
to the memory address at which the object
is stored in the heap.
All right, and so let's now again see in action,
what we just saw in the slides in the previous lecture.
And so what I want to do now is to copy this object here
into another object.
So let's pretend that this Jessica did marry
and changed her last name to something else.
So let's say marriedJessica should be equal to Jessica.
As we already know, this is not really gonna work,
but again, we want to actually see that problem
that we just talked about here in practice.
So let's say marriedJessica.lastname
should now change to Davis.
And so then let's log to the console,
the result of these two things.
So before, and then just jessica,
and I'm not sure if we ever did this,
so logging two things to the console,
but this is a nice trick that I like to use,
which is first to log a string basically as a label
of what I'm logging then here second.
So this function, this console.log function accepts
also multiple arguments
and then all of them will be logged to the console.
So here then after should be marriedJessica.
And now before saving this code
and reloading the browser,
try to guess what the output will be.
So did you do that?
Well then let's save and let's see.
And so here the after object,
indeed we get the last name as Davis
as we just changed it here.
But then the strange thing again
is that the last name also changed to Davis
in the original object.
So this one here before,
so this original jessica object, right?
So this is extremely strange, right?
Well not for you anymore,
because you already learned in the previous lecture
why exactly this is happening.
So this is happening
because when we tried to copy the original jessica object,
so right here,
it did actually not create a new object in the heap.
Instead this marriedJessica is simply
the exact same reference as jessica.
And so now marriedJessica and jessica are two variables
that point to the exact same object in the heap.
And so of course it makes total sense
that if we change a property here on marriedJessica,
then that change will also get reflected
in the variable Jessica, so this one right here,
again, because they are essentially just two different names
for the same thing.
Now by the way,
this is actually also the reason why we can change
properties on the marriedJessica object,
which was declared using a const,
and also on the Jessica object itself.
So again, these two were actually declared using const,
which we learned earlier are for constants.
So we learned back then that we cannot change
the value of a constant, right?
But we can still change the property values
like we just did here, right?
And so again, that's because we're not actually changing
the memory address, so the reference to the object,
that is stored here in the constant.
What we could not do
would to actually assign it a brand new object.
So we could not do actually this.
So we could not do, jessica should be equal
some new object with x 23.
So here we would get an error:
Assignment to constant variable.
But we can do something like this.
Age should be equal 30.
So here it's not a problem
because we're not changing the reference
that is stored inside this jessica constant.
All right, so again, just to make this completely clear,
what we did here is not okay,
because this year is a brand new object
and so it will get a new reference in the heap.
And so then here we are attempting to assign
that brand new reference to this variable here,
which is a constant.
And so here we're really trying
to change the value itself this time.
And so this is not allowed in a constant.
It would be allowed if this was a let.
So then here we wouldn't get any problem.
But again, if it is a const, we cannot do this.
So this is a fundamental very important difference.
And so please make sure
that you really understand this part.
Now let's just make this here slightly more interesting
by actually transforming this here into a function.
So just so you see that the same thing
will also happen when we pass an object to a function.
So let's say marryPerson,
and so this will then receive the person object
with a new last name.
So we're basically gonna create a reusable way
of doing what we had here.
So here then the person that it will receive,
and let's actually call this function first,
which many times makes it easier to see
how to actually do this.
So again, we basically want to replace these two lines here.
And so let's say
that we want the marriedJessica to be equal
of calling this function.
And then with the original person,
which is Jessica, and then with the new last name,
which remember was David, or Davis.
So here, let's call it actually originalPerson
just to make this a bit more clear.
And then here we just do what we did earlier here.
So we just say originalPerson.lastName
should be equal, the newLastName.
And then we just return the originalPerson.
So basically we just changed the last name here.
And so now here we get again the last name Davis
after the marriage,
but also in the original Jessica object,
which is this one right here.
So what this means, again,
is that we have the same situation as before,
even though this time we didn't manually copy
the object like we did here.
But what we did do
was to pass the object into the function here.
And so this originalPerson then becomes this object here,
but it will, just like before,
be the exact same object in the heap.
So only the reference is copied
or passed into the function.
And then as we change this originalPerson object,
what we're actually changing is this jessica object
that we passed in into the function.
And so then we get the last name Davis
in the original and in the marriedJessica.
All right, so very important to understand
that here in this situation as we call the function,
basically the same thing happens as right here.
And since this situation here is way more common,
it's important to keep that in mind.
So objects are not really copied when we pass them
into a function, but instead we only pass the reference,
and so it is still the same object in the heap
inside the function
as it is outside the function like here.
All right, but now what if we actually wanted to
really, really copy the object itself,
so that we could then change one without changing the other?
Or in other words, let's say that we now want to create
a brand new object in the heap,
but which looks exactly like the original object.
So again, that's actually what we wanted to do here
but couldn't really do,
because this is not how we create a true copy of an object.
So for this, let's actually create a new object.
So I will just copy that one
and then we will add another property here,
which is gonna be the family.
And here let's specify an array.
And let's say that Alice and Bob are the family of Jessica.
Let's call this here, jessica2.
And so this is the object that we now want to really copy.
So creating again, a brand new array
or a brand new object actually in the heap,
but which contains basically the exact same properties.
So let's say jessicaCopy.
And then here the way we do this
is by using something called the spread operator
and more about what the spread operator actually is.
But the way we use it is to create,
as we just said before, a brand new object.
And then we can use these three dots
and then here jessica2.
And actually let's change the names here.
So I want to call this one here, jessica1.
Let's then change that here and here and here,
and then this one here, just Jessica,
so to keep our code a bit more readable in here.
Okay, so again here, this is the spread operator,
which basically places all the properties
of this jessica object here into a brand new object,
which is what we're specifying here
with these new curly braces.
So these are creating a brand new object,
and then all the properties of jessica are placed in there.
And so then really a new object is created in the heap,
and the reference to that object
will be stored here in jessicaCopy.
And so now if we do jessicaCopy.lastName
and set it again to Davis.
So that's again, log to the console.
And now let's just log both of them at the same time here,
so jessica and jessicaCopy.
Well then here we get an unexpected result.
Ah, but that's because here I created .newLastName.
So that was a mistake, maybe you saw that.
So here it should of course be a lastName,
so just like here.
So we're changing the last name to Davis.
And so yeah, here we actually get the result
that we were looking for.
So the original keeps the Williams as the last name
and then the new one, so the copy,
has Davis as the last name,
so as we changed it here.
And so with this, we kept the original object
completely intact because in fact we now only
mutated the last name.
So we updated
or changed this last name on the copy,
which is a brand new object in the heap.
However, this is still not perfect.
So there is still a problem.
So let's experiment with something here
so that I can show you what I mean.
So let's say jessicaCopy
and then .family,
which remember is this array right here,
and then let's place a few more names in here.
Because basically when Jessica marries,
she gets some more new members into her family.
So let's also add Mary
and also another one.
So let's say John here.
All right, then let's log it to the console.
Let's maybe get rid of this earlier one here.
And I'm just gonna grab this one.
So here it's now jessica and jessicaCopy.
So remember how we pushed these two elements here
into the family array of jessicaCopy.
So only this jessicaCopy should be affected, right?
Well, let's see if that is actually the case.
So give ourselves a bit more space.
Open up these two,
and now notice how both the after,
so after the marriage and the before,
both have Mary and John added to the family.
Well, that's very strange, right?
Didn't we just create a brand new object in here?
Well, yes we did.
But remember how I said that what this does is basically
to copy all the properties
of this Jessica object into the new object.
But notice that this family here is actually an object,
because remember, our arrays are just objects.
And so this is essentially just like a variable
inside the Jessica object,
which means that this object here is again in the heap,
and this here just holds a reference to this other object.
So this is what's happening here.
We have an object.
And so then in that object we have a primitive,
another primitive and another primitive,
so here everything is straightforward.
But then here we have another object,
so basically a nested object.
And so this will get a brand new object in the heap,
and this family property will point,
so it will create an object reference to this object.
And so what we did here when we copied the properties
of the jessica object was to also copy the reference
to this array, so to this object right here,
which means that both jessica
and jessicaCopy have the family property,
which both point to the same object in the heap.
So essentially what we did here, so this,
a copy that we made here,
only copied the first level of the object,
but not the nested object.
So since we only copied the first level of the object,
so basically these primitives right here,
which were really copied,
then this is what we call a shallow copy,
so again, only the first level.
And shallow copy is a term
that you will hear a lot in JavaScript.
So again, this other nested object here
hasn't really been copied.
So jessica and or actually jessicaCopy and jessica,
they're both having their family property
pointing to the exact same array.
And so therefore as we push these two elements
into the array using the jessicaCopy variable,
the same thing will appear in the original jessica object.
So let's write that here,
so that we have a shallow copy,
which didn't really solve the problem that we wanted
to solve in the first place, right?
We wanted really a complete copy of this entire thing,
not just the first level.
And so in other words, what we wanted is a deep copy,
which is also called a deep clone.
And so this then copies the entire object,
including all the nested objects.
And in the real world,
oftentimes this is exactly what we want.
So oftentimes we need to deeply clone an object,
for example, when we want
to manipulate some big object in our code while ensuring
that the original data always stays the same.
So let's do that here.
So, now let's do the deep copy
or a deep clone as we could also call it.
So let's call this one here, the jessicaClone.
So it could be called a copy or a clone.
You'll hear both of these terms.
And so for that,
we now have the new structured clone function
that is now available in all modern browsers.
So again, this is actually pretty new.
And so in older browsers this will not work,
but don't worry about that for now.
So again, it is called structuredClone.
So actually just that suggestion
that was there on the screen.
And then we just pass it the object that we want to clone.
So that is indeed jessica.
And so let's now try this exact same thing,
but with the clone.
So Clone,
and then also this one here,
so that we don't have to type so much.
Here just to distinguish it from the other ones,
let's say after the clone,
or actually just, let's just say clone here
and maybe original.
So here we get for jessicaClone.
And let's see.
So this is the original.
This is the clone.
And as you see, we still have the Mary
and John here from earlier.
So it's been added here and here,
but this is still from this part.
So let's comment out maybe all of this.
And for this, I'm actually using a VS Code shortcut.
I'm not sure if I mentioned this earlier.
It is just Command or Control on Windows,
and then the slash, so this right here.
So that's a bit easier than just typing it out.
And so let's see that again.
And so now beautiful.
Our original nested object here stays the same.
So it is still only this original,
but then in our clone we actually get Mary
and John added to it without it being added to the original.
So that was the problem we had here earlier,
but now our structured clone solved that problem.
So this function here can be pretty important.
And so this is one of the big takeaways of this lecture.
Besides understanding how this whole thing works,
also keep in mind that with this function here,
you can create deep clones of objects.
And this was actually a lot harder a few years ago
because back then we had
to use an external library like Lodash
if we wanted to create deep clones.
But now we have this structuredClone function,
which has been added to browsers,
which makes our lives a lot easier.
So this is the big difference between a shallow copy
and a deep copy.
And always keep this in mind
because you will hear about this a lot when you work
with JavaScript in the future.