JavaScript 的物件是傳參考的,稍不注意就會讓原始資料被意外修改。本文整理四種深拷貝方法,說明各自的限制與適用場景。
深拷貝 vs 淺拷貝:關鍵差異
- 淺拷貝:只複製第一層屬性,內部物件仍然共享參考
- 深拷貝:遞迴複製所有層級,建立完全獨立的新物件
實作方法 1:使用 JSON 方法
最簡單的深拷貝寫法:
1 | function jsonDeepCopy(obj) { |
優點:
- 寫法簡單,零依賴
- 適用於只含字串、數字、布林值、null 的普通物件
缺點:
- 函式屬性會直接消失
undefined值會被丟棄- 無法處理循環引用(直接拋錯)
Date會被轉成 ISO 字串,JSON.parse後變成 string 而非 Date 物件;RegExp則變成空物件{}
實作方法 2:遞迴實作
1 | function deepCopy(obj, hash = new WeakMap()) { |
優點:
- 支援 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 | const original = { |
優點:
- 原生 API,無額外依賴
- 正確處理 Date、RegExp、Map、Set、ArrayBuffer、循環引用
- 效能通常優於手刻遞迴
缺點:
- 不支援函式(會拋
DataCloneError) - 不支援 DOM 節點、class 實例的原型鏈(只複製資料,不複製方法)
- 舊版瀏覽器(如 IE、Safari 15.3 以下)不支援
實作方法 4:使用 Lodash cloneDeep
1 | const _ = require('lodash'); |
優點:
- 功能最完整,邊角案例處理最全面
- 長期維護、大量專案驗證過
缺點:
- 需要引入額外依賴(若只為了 cloneDeep 引入整包 Lodash 成本偏高,可考慮
lodash.clonedeep單獨安裝) - 效能比
structuredClone慢
如何選擇
| 情境 | 建議方法 |
|---|---|
| 資料只有基本型別,快速了事 | JSON 方法 |
| 現代瀏覽器 / Node.js 17+,無函式屬性 | structuredClone |
| 需要複製函式,或要自訂複製邏輯 | 遞迴實作 |
| 專案已用 Lodash,或需要最高相容性 | _.cloneDeep |
效能上,structuredClone 通常快於手刻遞迴,Lodash cloneDeep 因為處理最多邊角案例,速度相對最慢;但在絕大多數實際場景下差距可以忽略,選對方法比調效能重要。
本部落格所有文章除特別聲明外,均採用CC BY-NC-SA 4.0 授權協議。轉載請註明來源 kyosora 筆記!
評論





