【发布时间】:2018-03-24 14:16:32
【问题描述】:
我知道这个问题已经讨论过很多次了,我想我有一个基本的想法。我从 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的每一层,所以我可以称之为“深拷贝”。
但是,如果 spread 运算符 仅有时创建深拷贝,那么 我如何测试新对象是否为深拷贝?
更新:我在clone4 中评论了NBAChampion,所以现在NBAChampion 是参考而不是复制!如果我在user.highlights.NBAChampion 中推送一个新值,clone4 也会更新。
我们应该怎样称呼这种类型的对象?它既不是浅拷贝也不是深拷贝。
为什么这很重要?
React 有一个比较浅拷贝的shouldComponentUpdate() 函数。有link。
在 React source code (Line: 356) 中,浅比较是这样完成的:
shouldComponentUpdate(nextProps) {
return this.props.children !== nextProps.children;
}
在上面的代码演示中,console.log 中的第二个和第三个参数显示了clone 和user 之间的比较结果。但是,只有第一个副本返回 true。 (注意:严格比较和抽象比较没有区别)
如果我将shouldComponentUpdate 应用于上面的演示,显然只有james 和user 会返回true。所以james 是 Facebook 代码中的浅拷贝。那么我的问题是:
- 在 JS 中引用和浅拷贝是完全一样的吗?如果不是,为什么 React 这样做?
- 如何在我的测试用例中测试一个对象是浅拷贝还是深拷贝?
这个问题花了我很多时间来制作。欢迎任何带有示例的清晰解释。
非常感谢。
【问题讨论】:
-
clone是浅拷贝。 “name”和“age”的原始(和不可变)值是副本,是的,但是对“highlights”对象的引用也是如此;这是参考的副本。 -
"在 JS 中引用和浅拷贝完全一样吗?如果不是,为什么 React 这样做?" - 引用和浅拷贝当然不是一回事。你觉得 React 的肤浅比较到底有什么不直观的地方?此外,詹姆斯不是用户的浅拷贝。而且 React 源代码的链接似乎不正确。
标签: javascript reactjs ecmascript-6