JavaScript 的物件是傳參考的,稍不注意就會讓原始資料被意外修改。本文整理四種深拷貝方法,說明各自的限制與適用場景。

深拷貝 vs 淺拷貝:關鍵差異

  • 淺拷貝:只複製第一層屬性,內部物件仍然共享參考
  • 深拷貝:遞迴複製所有層級,建立完全獨立的新物件

實作方法 1:使用 JSON 方法

最簡單的深拷貝寫法:

1
2
3
4
5
6
7
8
9
function jsonDeepCopy(obj) {
return JSON.parse(JSON.stringify(obj));
}

const original = {
name: 'John',
info: { age: 25 }
};
const copy = jsonDeepCopy(original);

優點:

  • 寫法簡單,零依賴
  • 適用於只含字串、數字、布林值、null 的普通物件

缺點:

  • 函式屬性會直接消失
  • undefined 值會被丟棄
  • 無法處理循環引用(直接拋錯)
  • Date 會被轉成 ISO 字串,JSON.parse 後變成 string 而非 Date 物件;RegExp 則變成空物件 {}

實作方法 2:遞迴實作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
function deepCopy(obj, hash = new WeakMap()) {
// 處理 null 或非物件
if (obj === null || typeof obj !== 'object') {
return obj;
}

// 處理日期物件
if (obj instanceof Date) {
return new Date(obj);
}

// 處理正則表達式(需帶入 source 與 flags,否則 flags 會遺失)
if (obj instanceof RegExp) {
return new RegExp(obj.source, obj.flags);
}

// 處理循環引用
if (hash.has(obj)) {
return hash.get(obj);
}

// 建立新物件或陣列
const copy = Array.isArray(obj) ? [] : {};

hash.set(obj, copy);

Object.keys(obj).forEach(key => {
copy[key] = deepCopy(obj[key], hash);
});

return copy;
}

優點:

  • 支援 Date、RegExp、循環引用
  • 可依需求擴充(Map、Set、Symbol 等)

缺點:

  • 程式碼量較多,需要自行維護
  • 深度嵌套時效能不如原生方案
  • 此版本不處理 Map、Set、Symbol key,有需要要自行補上

實作方法 3:使用 structuredClone

structuredClone() 是瀏覽器原生 API,Chrome 98、Firefox 97、Safari 15.4(2022 年 3 月)起全面支援,Node.js 17+ 也內建:

1
2
3
4
5
6
7
const original = {
name: 'John',
info: { age: 25 },
date: new Date()
};

const copy = structuredClone(original);

優點:

  • 原生 API,無額外依賴
  • 正確處理 Date、RegExp、Map、Set、ArrayBuffer、循環引用
  • 效能通常優於手刻遞迴

缺點:

  • 不支援函式(會拋 DataCloneError
  • 不支援 DOM 節點、class 實例的原型鏈(只複製資料,不複製方法)
  • 舊版瀏覽器(如 IE、Safari 15.3 以下)不支援

實作方法 4:使用 Lodash cloneDeep

1
2
const _ = require('lodash');
const copy = _.cloneDeep(original);

優點:

  • 功能最完整,邊角案例處理最全面
  • 長期維護、大量專案驗證過

缺點:

  • 需要引入額外依賴(若只為了 cloneDeep 引入整包 Lodash 成本偏高,可考慮 lodash.clonedeep 單獨安裝)
  • 效能比 structuredClone

如何選擇

情境 建議方法
資料只有基本型別,快速了事 JSON 方法
現代瀏覽器 / Node.js 17+,無函式屬性 structuredClone
需要複製函式,或要自訂複製邏輯 遞迴實作
專案已用 Lodash,或需要最高相容性 _.cloneDeep

效能上,structuredClone 通常快於手刻遞迴,Lodash cloneDeep 因為處理最多邊角案例,速度相對最慢;但在絕大多數實際場景下差距可以忽略,選對方法比調效能重要。