I know this question has been discussed so many times, and I think I got a basic idea. There are some top rated answers I found from StackOverflow:
But all the answers seems very fuzzy to me.
Let's consider the example below:
const user = {
name: "James",
age: 33,
highlights: {
career: "Basketball player",
NBAChampion: [2012, 2013, 2016],
},
promotion: () => ("Get LeBron15 now!"),
};
const james = user;
const clone = { ...user };
const clone2 = Object.assign({}, user);
const clone3 = JSON.parse(JSON.stringify(user));
const clone4 = {
...user,
highlights: {
...user.highlights,
// I comment the it out, so now NBAChampion is a reference rather than copy!
// NBAChampion: [...user.highlights.NBAChampion]
}
};
user.age++;
user.highlights.career = "football player";
console.log('james', james, james === user, james == user);
console.log('clone', clone, clone === user, clone == user);
console.log('clone2', clone2, clone2 === user, clone2 == user);
console.log('clone3', clone3, clone3 === user, clone3 == user);
// console.log(clone3.promotion()); // My problem with clone3 is that function's been removed.
console.log('clone4', clone4, clone4 === user, clone4 == user);
james
is a reference, it's always exactly same as user;clone
is a copy. Is it a shallow copy or deep copy? Thename
andage
are separated fromuser
, but thehighlights
is still a reference.clone2
behaves exactly the same asclone
.clone3
is converted from a string. Is it a deep copy? It is not a perfect clone, since functions (if there's any) are not save to convert this way.clone4
is copied every layer ofuser
, so I can call it a "deep copy".
However if the spread operator only creates deep copy sometimes, then how can I test if the new object is a deep copy or not?
Update: I commented NBAChampion
out in clone4
, so now NBAChampion is a reference rather than copy! If I push a new value in user.highlights.NBAChampion
, clone4
will also updates.
What should we call this type of object? It's neither a shallow nor deep copy.
Why does this matter?
React has a shouldComponentUpdate()
function which compares shallow copy. There is the link.
In React source code (Line: 356), the shallow comparison is done like this:
shouldComponentUpdate(nextProps) {
return this.props.children !== nextProps.children;
}
In the code demo above, the 2nd and 3rd parameters in console.log
show the comparison results between clone
and user
. However, only 1st copy returns true
. (Note: there is no different between strict comparison and abstract comparison)
If I apply shouldComponentUpdate
to the demo above, obviously only james
and user
will return true
. So james
is a shallow copy in Facebook's code. Then my questions are:
- Are reference and shallow copy exactly the same thing in JS? If not, why React do this?
- How can I test a object is a shallow copy or deep copy in my test case?
The question took me lots of time to craft. Any clear explanation with example is welcome.
Thanks a lot.