我知道这个问题已经讨论过很多次了,我想我有了一个基本的想法。我在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的每一层,所以我可以称之为“深拷贝”。
然而,如果扩展运算符只创建深拷贝(有时是),那么如何测试新对象是否是深拷贝?Update:我在clone4中注释了NBAChampion,所以现在NBAChampion是引用而不是复制!如果我在user.highlights.NBAChampion中推送一个新值,clone4也会更新。
,我们应该把这种类型的对象称为什么?,它既不是浅层的,也不是深层的。
这有什么关系?
React有一个比较浅拷贝的shouldComponentUpdate()函数。这是链接。
在React 源代码(行: 356)中,浅比较如下所示:
shouldComponentUpdate(nextProps) {
return this.props.children !== nextProps.children;
}在上面的代码演示中,console.log中的第二个和第三个参数显示了clone和user之间的比较结果。然而,只有第一份副本返回true。(注:严格比较与抽象比较没有区别)
如果我将shouldComponentUpdate应用于上面的演示,显然只有james和user会返回true。因此,james在Facebook的代码中只是一个浅薄的副本。那么我的问题是:
这个问题花了我很长的时间才能解决。任何有例子的明确解释都是欢迎的。
非常感谢。
发布于 2018-03-24 14:35:58
让我们考虑下面的例子
clone和clone2是浅浅的,只影响原始对象的属性。clone3和clone4都很深。
但是,如果扩展操作符有时只创建深拷贝,那么如何测试新对象是否是深拷贝?
它在clone4的情况下创建深度复制--只要深度由开发人员控制。通常,不需要测试一个对象是深拷贝的,还是反应不同的,因为这个检查很昂贵,需要遍历两个比较对象中的嵌套对象,并按属性比较它们的属性。
性能是反应依赖于不变性的原因。如果一个新值不等于===,那么它被认为是一个不同的值。
所以,在Facebook的代码中,james只是一个浅薄的复制品。
它不是,它是一个被分配给另一个变量的引用。还是一样的东西。
引用和浅层复制在JS中是完全相同的吗?
推荐信不是副本。所以这也不是浅薄的抄袭。
我在NBAChampion中注释了clone4,所以现在NBAChampion是一个引用而不是复制!如果我在user.highlights.NBAChampion中推送一个新值,clone4也会更新。我们应该如何称呼这种类型的对象?这既不是浅薄的也不是深的复制。
只是一份副本。它没有特定的名称,因为很少需要做这样的选择性拷贝。如果目的是让它像深抄袭一样,那它就应该被称为错误。
发布于 2018-03-24 14:26:27
对象(或数组)的浅拷贝是一个单独的对象,具有匹配的属性名和属性值集。
在创建一个浅拷贝之后,对两个对象(原始和复制)的属性按属性进行比较,将显示所有属性值都是===。
例如:
let o1 = { a: 1, b: 2, c: { x: "hello", y: "world" } };
let o2 = {};
Object.keys(o1).forEach(propertyName => o2[propertyName] = o1[propertyName]);现在,如果比较o1和o2的属性值,它们当然是===。特别是,两个对象的属性"c“将是对带有"x”和"y“属性名称的子对象的引用。但是,将o1和o2与==或===进行比较并不会显示相等,因为无论内容如何,两个不同的对象从来都不是彼此的==。
对象的深拷贝是将源的每个对象值属性递归地深复制到目标副本中的副本。因为必须为深拷贝目标创建新的对象值,所以这些属性值不能与===相比较,因为没有两个不同的对象可以是===。
用JavaScript这样的语言进行深度复制可能会有问题,因为来自属性值的引用的“图”可以是循环的,而且某些属性值可能是函数。通常,深度复制方法必须根据应用程序对应用程序进行一些假设。
根据我的经验,与浅层复制相比,需要对对象进行深度复制是非常罕见的。
现在,抛开所有这些,在两个对象引用之间进行比较,就像在您的React代码中一样:
shouldComponentUpdate(nextProps) {
return this.props.children !== nextProps.children;
}与浅薄或深拷贝无关。这是两个名为“子”的对象属性之间的单个比较。this.props和nextProps引用的对象可能是不同的对象,也可能是相同的对象,其中一个可能是另一个的浅拷贝或深拷贝,但这对比较语句没有什么影响:所做的只是比较两个特定的“子”属性值,以获得严格的不平等。(的确,如果nextProps碰巧是this.props的浅表副本,反之亦然,那么!==比较将是错误的,但是比较不必知道这两个对象的历史;它只是两个值的一个比较。)
https://stackoverflow.com/questions/49465712
复制相似问题