淺複製

物件的淺複製是這樣一種複製:它的屬性與源物件(從中建立複製的物件)的屬性共享相同的引用(指向相同的底層值)。因此,當你改變源物件或複製物件時,可能會導致另一個物件也隨之改變。這種行為與深複製的行為形成對比,深複製中源物件和複製物件是完全獨立的。

更正式地講,如果以下條件成立,則兩個物件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"]}]

另見