iT邦幫忙

1

JavaScript 深拷貝(Deep Copy)

  • 分享至 

  • xImage
  •  

在 JavaScript 中,深拷貝(Deep Copy)是一種創建對象完整副本的方式,其中所有的嵌套對象或數組也會被拷貝,而不是共享原始對象的引用。以下是一些常見的深拷貝方法:

1. JSON 方法

使用 JSON.stringify() 和 JSON.parse() 將對象轉換為 JSON 字符串後再解析為新對象。

const obj = { a: 1, b: { c: 2 } };
const deepCopy = JSON.parse(JSON.stringify(obj));

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

優點:

簡單易用,適合純 JSON 結構(不含函數、undefined、Symbol 等)。

缺點:

不能處理循環引用(如 obj.a = obj)。
丟失特殊數據類型(如 Date、Set、Map 等)。

2. 遞歸拷貝

手動實現遞歸拷貝,適合處理更複雜的數據結構。

function deepCopy(obj) {
  if (obj === null || typeof obj !== "object") return obj;

  // 處理數組
  if (Array.isArray(obj)) {
    return obj.map(item => deepCopy(item));
  }

  // 處理對象
  const copy = {};
  for (const key in obj) {
    if (obj.hasOwnProperty(key)) {
      copy[key] = deepCopy(obj[key]);
    }
  }
  return copy;
}

const obj = { a: 1, b: { c: 2 }, d: [3, 4] };
const deepCopyObj = deepCopy(obj);

console.log(deepCopyObj); // { a: 1, b: { c: 2 }, d: [3, 4] }
console.log(deepCopyObj.b === obj.b); // false

優點:

  • 可完全控制深拷貝的行為。
  • 能處理循環引用(需要額外的邏輯)。

缺點:

  • 實現複雜,需要處理特殊情況(如循環引用)。

3. 使用第三方庫

Lodash 的 cloneDeep
Lodash 提供了一個高效且功能強大的深拷貝方法。

const _ = require("lodash");

const obj = { a: 1, b: { c: 2 }, d: [3, 4] };
const deepCopy = _.cloneDeep(obj);

console.log(deepCopy); // { a: 1, b: { c: 2 }, d: [3, 4] }
console.log(deepCopy.b === obj.b); // false

優點:

  • 處理各種數據類型和特殊情況(如循環引用)。
  • 使用簡單且可靠。

缺點:

  • 需要額外引入庫

4. 結合 structuredClone

structuredClone 是一個現代瀏覽器支持的內置方法,用於深拷貝。

const obj = { a: 1, b: { c: 2 }, d: [3, 4] };
const deepCopy = structuredClone(obj);

console.log(deepCopy); // { a: 1, b: { c: 2 }, d: [3, 4] }
console.log(deepCopy.b === obj.b); // false

優點:

  • 原生支持,無需外部庫。
  • 支持 Map、Set、Date 等數據類型。
  • 能處理循環引用。

缺點:

  • 需要現代瀏覽器支持(不支持 IE 等老舊瀏覽器)。

5. 使用 Object.assign 或擴展運算符結合遞歸

結合 Object.assign 或展開運算符,實現手動深拷貝。

function deepCopy(obj) {
  if (obj === null || typeof obj !== "object") return obj;

  const copy = Array.isArray(obj) ? [] : {};
  for (const key in obj) {
    if (obj.hasOwnProperty(key)) {
      copy[key] = deepCopy(obj[key]);
    }
  }
  return copy;
}

const obj = { a: 1, b: { c: 2 }, d: [3, 4] };
const deepCopyObj = deepCopy(obj);

console.log(deepCopyObj); // { a: 1, b: { c: 2 }, d: [3, 4] }
console.log(deepCopyObj.b === obj.b); // false

優點:

  • 與遞歸方法類似,但結合了更直觀的語法。

缺點:

  • 仍需處理特殊數據類型和循環引用。

6. 手動處理特殊數據類型

針對特定場景(如 Date、Map、Set),手動處理深拷貝。

function deepCopy(obj) {
  if (obj === null || typeof obj !== "object") return obj;

  if (obj instanceof Date) return new Date(obj);
  if (obj instanceof Map) return new Map([...obj]);
  if (obj instanceof Set) return new Set([...obj]);

  const copy = Array.isArray(obj) ? [] : {};
  for (const key in obj) {
    if (obj.hasOwnProperty(key)) {
      copy[key] = deepCopy(obj[key]);
    }
  }
  return copy;
}

const obj = { a: new Date(), b: new Map([[1, "one"]]), c: new Set([2, 3]) };
const deepCopyObj = deepCopy(obj);

console.log(deepCopyObj); // 深拷貝的對象,保持特殊類型

圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言