Notice how sherlock.address is an object. The object { city: 'London' }.
The code basically assigns the exact same object to john. So, sherlock and john live in the same house, that's fine. But then when john moves, it assigns Malibu to the city of his address, which is the exact same address object that sherlock is using, hence sherlock sees the change.
To fix this, instead of assigning the exact same address object, we need to make a copy.
There are many ways in Javascript to copy an object, but let's use this simple one (the object destructuring/spread operator syntax {...ojb}):
let john = {
surname: 'Watson',
address: {...sherlock.address}
};
This way, instead of using the object sherlock.address as is, we copied it. After this, when john changes his city, it will not reflect to sherlock.
Another way is to declare an address object for john and copy the city, like this:
let john = {
surname: 'Watson',
address: {city: sherlock.address.city}
};
Spread operator vs rest operator, ..., similar syntax, different purpose:
The Spread operator is used to make a copy of an object, or merge multiple objects together (notice how it is used in the object you want to copy:
const person = {name: "John", lastName: "Doe", age: 59, email: "johndoe@gmail.com"};
const personCopy = {...person};
console.log(personCopy); // {name: 'John', lastName: 'Doe', age: 59, email: 'johndoe@gmail.com'}
// Merging objects:
const moreProperties = {city: "New York", isActive: true};
const merged = {...person, ...moreProperties};
console.log(merged); // {name: 'John', lastName: 'Doe', age: 59, email: 'johndoe@gmail.com', city: 'New York', isActive: true}
The rest operator is used to assign all the properties or the rest of the properties of an object to a variable (notice how it goes in the new variable to you to assign the rest of the properties to):
const person = {name: "John", lastName: "Doe", age: 59, email: "johndoe@gmail.com"};
// Here I'm only extracting the name and lastName properties of the object into their corresponding variables. Then, I use the rest operator ... to assign the rest of the properties of person that I haven't extracted (copied) into the restOfTheProperties (could be named anything) variable, which is essencially a copy of all the remaining properties of the object.
const { name, lastName, ...restOfTheProperties} = person;
console.log(name); // "John"
console.log(lastName); // "Doe"
console.log(restOfTheProperties); // {age: 59, email: 'johndoe@gmail.com'}
It can also be used in function args, like this:
function etc(...args) {
console.log(args);
}
etc(1,2,3); // [1,2,3]
Could be used for arrays too.
More info here: https://www.freecodecamp.org/news/javascript-rest-vs-spread-operators/