js 淺複製和深複製的區別和應用

盘思动發表於2024-11-08

在 JavaScript 中,淺複製深複製都用於複製物件的內容,但它們在複製的方式和效果上有顯著的區別。理解它們的差異對於避免常見的 bug 和正確使用資料結構非常重要。

1. 淺複製(Shallow Copy)

淺複製是指建立一個新的物件,但新的物件中僅複製原始物件的第一層屬性(即原始物件的屬性值)。如果屬性值本身是一個物件或陣列,那麼它不會被複制,而是會保留對原始物件屬性的引用。

特點:

  • 淺複製只複製物件的“第一層”屬性,對於屬性值是物件或陣列的情況,它們仍然指向原始物件的引用。
  • 這樣修改複製物件中的巢狀物件會影響到原始物件中的巢狀物件。

例子:

const obj = { a: 1, b: { c: 2 } };

const shallowCopy = { ...obj };  // 使用擴充套件運算子進行淺複製
shallowCopy.a = 10;             // 修改第一層的屬性

shallowCopy.b.c = 20;          // 修改巢狀物件中的屬性

console.log(obj);              // { a: 1, b: { c: 20 } }
console.log(shallowCopy);      // { a: 10, b: { c: 20 } }

解釋:

  • shallowCopy.a = 10 只改變了第一層屬性 a 的值,原始物件 obj 中的 a 仍然是 1
  • shallowCopy.b.c = 20 影響了 b 這個巢狀物件,因為它們仍然引用了同一個物件。

常見的淺複製方法:

  • 使用 Object.assign()
    const shallowCopy = Object.assign({}, obj);
    
  • 使用擴充套件運算子(...):
    const shallowCopy = { ...obj };
    

2. 深複製(Deep Copy)

深複製是指建立一個新的物件,並且遞迴地複製原始物件的所有屬性,不管這些屬性的值是原始型別(如字串、數字、布林值等),還是引用型別(如物件、陣列等)。深複製會完全獨立於原始物件,因此修改新物件中的屬性不會影響原始物件。

特點:

  • 深複製會複製物件的所有層級,包括巢狀的物件或陣列,確保沒有任何引用關係。
  • 修改深複製後的物件,不會影響原始物件。

例子:

const obj = { a: 1, b: { c: 2 } };

const deepCopy = JSON.parse(JSON.stringify(obj));  // 使用 JSON 方法進行深複製
deepCopy.a = 10;
deepCopy.b.c = 20;

console.log(obj);          // { a: 1, b: { c: 2 } }
console.log(deepCopy);     // { a: 10, b: { c: 20 } }

解釋:

  • deepCopy 是透過 JSON.parse(JSON.stringify()) 實現的深複製,這種方法可以確保 obj 中的每一層都被複制,並且是完全獨立的。
  • 修改 deepCopy 中的屬性 ab.c 不會影響 obj,因為它們不再共享引用。

常見的深複製方法:

  • 使用 JSON.parse(JSON.stringify(obj))(但有侷限性,不能複製函式、undefinedSymbol 等,且無法處理迴圈引用)。
  • 使用遞迴方法手動實現深複製。
  • 使用第三方庫(如 LodashcloneDeep 方法)。
// 使用 Lodash 的 deep clone 方法
const _ = require('lodash');
const deepCopy = _.cloneDeep(obj);

3. 淺複製與深複製的區別總結

特性 淺複製 深複製
複製深度 僅複製一層(第一層)屬性 遞迴複製所有層級的屬性
對引用型別的處理 僅複製引用型別的引用 複製引用型別的內容,完全獨立
修改結果 修改巢狀物件會影響原始物件 修改複製物件不會影響原始物件
常見方法 Object.assign()、擴充套件運算子(... JSON.parse(JSON.stringify())、手動遞迴、Lodash.cloneDeep()

4. 淺複製和深複製的應用場景

  • 淺複製:

    • 用於複製物件的第一層屬性,但不需要複製巢狀物件。適用於僅需要修改一層資料的場景。
    • 在元件狀態管理中,如果物件的巢狀屬性沒有被修改,淺複製可以避免不必要的深度複製,提高效能。
  • 深複製:

    • 用於確保物件之間完全獨立,特別是當物件中包含巢狀的引用型別(如陣列或物件),且這些巢狀物件需要獨立修改時。
    • 在需要避免對原始資料進行修改(如在狀態管理中,或者操作不可變資料時)非常有用。

總結

  • 淺複製適用於只需要複製物件的第一層屬性的場景,且不會影響引用型別的修改。
  • 深複製適用於需要確保完全獨立的物件副本,尤其是在物件中包含巢狀引用型別時。

根據不同的應用場景選擇適當的複製方式,能有效提高程式碼的效率和可靠性。

相關文章