我不知道如何在 JS/TS 中建立深度克隆

王大冶發表於2024-11-06

image.png

  • React Hook 深入淺出
  • CSS技巧與案例詳解
  • vue2與vue3技巧合集
  • VueUse原始碼解讀

在JavaScript和TypeScript開發中,物件的深度克隆是一個常見但容易被誤解的話題。本文將探討幾種常用的克隆方法,揭示它們的侷限性,並介紹真正有效的深度克隆技術。

常見誤區:展開運算子和Object.create()

許多開發者習慣使用展開運算子{...}Object.create()來克隆物件,但這些方法實際上只能進行淺複製。

展開運算子的侷限性:

const original = { name: "John", address: { city: "New York" } };
const clone = { ...original };

clone.address.city = "Los Angeles";
console.log(original.address.city); // 輸出: "Los Angeles"

Object.create()的問題:

const original = { name: "John", address: { city: "New York" } };
const clone = Object.create(original);

clone.address.city = "Chicago";
console.log(original.address.city); // 輸出: "Chicago"

這兩種方法都無法實現真正的深度克隆,因為它們只複製了物件的頂層屬性。

JSON.parse(JSON.stringify()):簡單而有效

對於簡單物件,JSON.parse(JSON.stringify())是一個有效的深度克隆方法:

const original = { name: "John", address: { city: "New York" } };
const clone = JSON.parse(JSON.stringify(original));

clone.address.city = "San Francisco";
console.log(original.address.city); // 輸出: "New York"

然而,這種方法也有侷限性。它無法處理函式、undefinedInfinityNaN、正規表示式、Map和Set等複雜資料型別。

lodash.deepClone:全面而強大

對於需要處理複雜資料結構的場景,lodash.deepClone是一個更全面的解決方案:

import _ from 'lodash';

const original = {
  name: "John",
  address: { city: "New York" },
  skills: new Set(["JavaScript", "TypeScript"]),
  greet: function() { console.log("Hello!"); }
};

const clone = _.cloneDeep(original);

clone.address.city = "Boston";
clone.skills.add("React");

console.log(original.address.city); // 輸出: "New York"
console.log(original.skills.has("React")); // 輸出: false

lodash.deepClone能夠正確處理巢狀物件、陣列、函式,以及特殊的資料結構如Set和Map。

效能考慮

在效能方面,JSON.parse(JSON.stringify())通常對簡單物件更快,而lodash.deepClone對複雜結構更可靠但速度較慢。

// 效能測試示例
const simpleObject = { a: 1, b: 2, c: 3 };
const complexObject = { /* 複雜的巢狀結構 */ };

console.time('JSON Simple');
JSON.parse(JSON.stringify(simpleObject));
console.timeEnd('JSON Simple');

console.time('Lodash Simple');
_.cloneDeep(simpleObject);
console.timeEnd('Lodash Simple');

console.time('JSON Complex');
JSON.parse(JSON.stringify(complexObject));
console.timeEnd('JSON Complex');

console.time('Lodash Complex');
_.cloneDeep(complexObject);
console.timeEnd('Lodash Complex');

結論

在JavaScript和TypeScript中實現無突變的深度克隆可能比想象的更復雜。展開運算子和Object.create()雖然常用,但不適合深度克隆。JSON.parse(JSON.stringify())對於簡單物件是一個快速有效的解決方案,而lodash.deepClone則是處理複雜資料結構的理想選擇。

理解這些方法的優缺點對於選擇合適的克隆策略至關重要。在實際開發中,應根據具體需求和資料結構的複雜性來選擇適當的深度克隆方法。透過掌握這些技巧,開發者可以更有效地處理物件克隆,提高程式碼的健壯性和可維護性。

本文 GitHub https://github.com/qq449245884/xiaozhi 已收錄,有一線大廠面試完整考點、資料以及我的系列文章。

相關文章