淺複製
物件的淺複製是這樣一種複製:它的屬性與源物件(從中建立複製的物件)的屬性共享相同的引用(指向相同的底層值)。因此,當你改變源物件或複製物件時,可能會導致另一個物件也隨之改變。這種行為與深複製的行為形成對比,深複製中源物件和複製物件是完全獨立的。
更正式地講,如果以下條件成立,則兩個物件o1和o2是淺複製:
- 它們不是同一個物件(
o1 !== o2)。 o1和o2的屬性具有相同的名稱,且順序相同。- 它們屬性的值相等。
- 它們的原型鏈相等。
另請參閱結構等價的定義。
如果一個物件的屬性都具有原始值,那麼它的複製符合深複製和淺複製的定義。然而,談論這種複製的深度有些無意義,因為它沒有巢狀屬性,而我們通常在修改巢狀屬性的背景下談論深複製。
對於淺複製,只複製頂層屬性,而不復制巢狀物件的值。因此:
- 重新賦值複製的頂層屬性不會影響源物件。
- 重新賦值複製的巢狀物件屬性會影響源物件。
在 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"]}]