我知道这个问题已经讨论过很多次了,我想我已经有了一个基本的想法。我从 StackOverflow 找到了一些评分最高的答案:
但是所有的答案对我来说似乎都很模糊。
让我们考虑下面的例子:
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
是一个参考,它总是与用户完全相同;clone
是一个副本。是浅拷贝还是深拷贝?的name
和age
从分离user
,但highlights
仍然是一个参考。clone2
行为与 完全相同clone
。clone3
从字符串转换而来。是深拷贝吗?它不是一个完美的克隆,因为函数(如果有的话)不能以这种方式进行转换。clone4
的每一层都被复制user
,所以我可以称之为“深度复制”。
但是,如果扩展运算符有时只创建深拷贝,那么我如何测试新对象是否为深拷贝?
更新:我在 中注释掉NBAChampion
了clone4
,所以现在 NBAChampion 是参考而不是复制!如果我在 中推送新值user.highlights.NBAChampion
,clone4
也会更新。
我们应该怎么称呼这种类型的对象?它既不是浅拷贝也不是深拷贝。
为什么这很重要?
React有一个shouldComponentUpdate()
比较浅拷贝的功能。有链接。
在 React源代码 (Line: 356) 中,浅比较是这样完成的:
shouldComponentUpdate(nextProps) {
return this.props.children !== nextProps.children;
}
在上面的代码演示中,第 2 个和第 3 个参数console.log
显示了clone
和之间的比较结果user
。但是,只有第一个副本返回true
。(注:严格比较和抽象比较没有区别)
如果我申请shouldComponentUpdate
上面的演示,显然只有james
并且user
会返回true
. james
Facebook 代码中的浅拷贝也是如此。那么我的问题是:
- JS 中的引用和浅拷贝是一回事吗?如果没有,为什么 React 这样做?
- 如何在我的测试用例中测试对象是浅拷贝还是深拷贝?
这个问题花了我很多时间来设计。欢迎任何带有示例的清晰解释。
非常感谢。