此页面由社区从英文翻译而来。了解更多并加入 MDN Web Docs 社区。
浅拷贝
对象的浅拷贝是属性与拷贝的源对象属性共享相同的引用(指向相同的底层值)的副本。因此,当你更改源对象或副本时,也可能导致另一个对象发生更改。与之相比,在深拷贝中,源对象和副本是完全独立的。
形式化地,如果两个对象o1 和o2 是浅拷贝,那么:
- 它们不是同一个对象(
o1 !== o2)。 o1和o2的属性具有相同的名称且顺序相同。- 它们的属性值相等。
- 它们的原型链相等。
参见结构等价的定义。
所有属性都是原始值的对象的副本同时符合深拷贝和浅拷贝的定义。然而,讨论这种副本的深度并无意义,因为它没有嵌套属性,而我们通常在修改嵌套属性的上下文中讨论深拷贝。
对于浅拷贝,只有顶层属性被复制,而不是嵌套对象的值。因此:
- 对副本的顶层属性的重新赋值不会影响源对象。
- 对副本的嵌套对象属性的重新赋值会影响源对象。
在 JavaScript 中,所有标准内置对象复制操作(扩展语法、Array.prototype.concat()、Array.prototype.slice()、Array.from() 和Object.assign())都创建浅拷贝,而不是深拷贝。
考虑以下示例,其中创建了一个ingredientsList 数组对象,然后通过复制该ingredientsList 对象创建了一个ingredientsListCopy 对象。
js
const ingredientsList = ["面条", { list: ["鸡蛋", "面粉", "水"] }];const ingredientsListCopy = Array.from(ingredientsList);console.log(ingredientsListCopy);// ["面条",{"list":["鸡蛋","面粉","水"]}]对嵌套属性的重新赋值将在两个对象中可见。
js
ingredientsListCopy[1].list = ["粘米粉", "水"];console.log(ingredientsList[1].list);// Array [ "粘米粉", "水" ]对顶层属性的重新赋值(在这种情况下是0 索引)只会在更改的对象中可见。
js
ingredientsListCopy[0] = "米线";console.log(ingredientsList[0]); // 面条console.log(JSON.stringify(ingredientsListCopy));// ["米线",{"list":["粘米粉","水"]}]console.log(JSON.stringify(ingredientsList));// ["面条",{"list":["粘米粉","水"]}]