浅拷贝

对象的浅拷贝是指其属性与创建该拷贝的源对象的属性共享相同的引用(指向相同的基础值)。因此,当您更改源对象或拷贝时,您也可能会导致另一个对象也发生更改。这种行为与深拷贝的行为形成对比,在深拷贝中,源对象和拷贝是完全独立的。

更正式地说,如果两个对象o1o2是浅拷贝,则

  1. 它们不是同一个对象 (o1 !== o2)。
  2. o1o2的属性具有相同的名称,并且顺序相同。
  3. 其属性的值相等。
  4. 它们的原型链相等。

另请参阅结构等价的定义。

如果对象的拷贝的所有属性都具有原始值,则该拷贝既符合深拷贝的定义,也符合浅拷贝的定义。但是,讨论这种拷贝的深度有点没有意义,因为它没有嵌套属性,并且我们通常在修改嵌套属性的上下文中讨论深拷贝。

对于浅拷贝,仅复制顶层属性,而不复制嵌套对象的属性值。因此

  • 重新分配拷贝的顶层属性不会影响源对象。
  • 重新分配拷贝的嵌套对象属性会影响源对象。

在 JavaScript 中,所有标准的内置对象复制操作(扩展语法Array.prototype.concat()Array.prototype.slice()Array.from()Object.assign())都会创建浅拷贝,而不是深拷贝。

考虑以下示例,其中创建了一个ingredientsList数组对象,然后通过复制该ingredientsList对象创建了一个ingredientsListCopy对象。

js
const ingredientsList = ["noodles", { list: ["eggs", "flour", "water"] }];

const ingredientsListCopy = Array.from(ingredientsList);
console.log(ingredientsListCopy);
// ["noodles",{"list":["eggs","flour","water"]}]

重新分配嵌套属性的值将在两个对象中都可见。

js
ingredientsListCopy[1].list = ["rice flour", "water"];
console.log(ingredientsList[1].list);
// Array [ "rice flour", "water" ]

重新分配顶层属性的值(在本例中为索引0)仅在已更改的对象中可见。

js
ingredientsListCopy[0] = "rice noodles";
console.log(ingredientsList[0]); // noodles
console.log(JSON.stringify(ingredientsListCopy));
// ["rice noodles",{"list":["rice flour","water"]}]
console.log(JSON.stringify(ingredientsList));
// ["noodles",{"list":["rice flour","water"]}]

另请参阅