JavaScript 中 structuredClone 和 JSON.parse(JSON.stringify()) 克隆物件的區別

日升_rs發表於2024-09-06

JavaScript 中 structuredClone 和 JSON.parse(JSON.stringify()) 克隆物件的異同點

一、什麼是 structuredClone?

1. structuredClone 的發展

structuredClone 是在 ECMAScript 2021(ES12)標準中引入的,ECMAScript 2021 規範正式釋出於 2021 年 6 月

自 2022 年 3 月起,該功能適用於最新的裝置和瀏覽器版本

Baseline 2022 Newly available
Since March 2022, this feature works across the latest devices and browser versions. This feature might not work in older devices or browsers.

2. structuredClone 的功能

2.1. 功能

全域性的 structuredClone() 方法使用結構化克隆演算法將給定的值進行深複製

2.2. 語法

structuredClone(value)
structuredClone(value, { transfer })

2.2. 引數

  • value:被克隆的物件
  • transfer:可轉移的陣列

2.3. 返回值

返回值是原始值的深複製

2.4.

如果輸入值的任一部分不可序列化,則丟擲 DataCloneError 異常

3. 用法

3.1. 普通用法

const obj = {
  name: '日升',
  sex: '男',
  blog: {
      csdn: 'https://guoqiankun.blog.csdn.net/?type=blog',
      jj: 'https://juejin.cn/user/2409752520033768/posts'
  },
  games: ['cf', '黑馬嘍', 'cs'],
  age: 18,
  bool: true,
  set: new Set([1,2,3]),
  map: new Map([['a', 'b'], ['c', 'd']]),
  null: null,
  und: undefined
}
const cloneObj = structuredClone(obj);

image

3.2. transfer 用法

transfer 是一個可轉移物件的陣列,裡面的值並沒有被克隆,而是被轉移到被複製物件上

const buffer = new ArrayBuffer(16);
console.log('buffer', buffer);
const cloned = structuredClone(buffer, { transfer: [buffer] });
console.log('buffer', buffer);
console.log('cloned', cloned);

image

二、structuredClone 和 JSON.parse(JSON.stringify()) 的區別

1. 支援的資料型別

從上面的示例中能看出,structuredClone 支援了很多中資料型別,基本型別和普通物件都支援

1.1. structuredClone

1.1.1. 支援的型別
  • 基本型別
  • 普通物件
  • Date 物件
  • RegExp 物件
  • Map
  • Set
  • ArrayBuffer
  • TypedArrays
  • Blob
  • File
  • ImageData
  • MessagePort
  • null、undefined
  • NaN、Infinity、-Infinity
  • 迴圈引用
1.1.2. 不支援的型別
  • 函式
  • symbol
  • WeakMap
  • WeakSet
  • HTMLElement
1.1.3. 示例
const port1 = new MessageChannel().port1
const obj = {
  date: new Date(),
  regex: /test/i,
  map: new Map([['key1', 'value1'], ['key2', 'value2']]),
  set: new Set([1, 2, 3]),
  arrayBuffer: new ArrayBuffer(8),
  typedArray: new Uint8Array([1, 2, 3]),
  blob: new Blob(['Hello, world!'], { type: 'text/plain' }),
  file: new File(['file content'], 'filename.txt', { type: 'text/plain' }),
  imageData: (() => {
    const canvas = document.createElement('canvas');
    const context = canvas.getContext('2d');
    return context.createImageData(100, 100);
  })(),
  messagePort: port1,
  nullValue: null,
  undefinedValue: undefined,
  nanValue: NaN,
  infinityValue: Infinity,
  negativeInfinityValue: -Infinity,
  circularRef: {}
};

// 建立迴圈引用
obj.circularRef.self = obj;

// 克隆 obj 物件
const clonedObj = structuredClone(obj, {transfer: [port1]});

// 輸出以驗證
console.log(clonedObj);

image

const obj = {
  func: function() { return "I'm a function"; },   // 函式
  symbol: Symbol('uniqueSymbol'),                  // Symbol
  weakMap: new WeakMap(),                          // WeakMap
  weakSet: new WeakSet(),                          // WeakSet
  element: document.createElement('div')           // HTMLElement
};

// 嘗試克隆物件
try {
  const clonedObj = structuredClone(obj);
  console.log(clonedObj); // This line won't run if an error is thrown
} catch (error) {
  console.error('Error:', error); // DataCloneError: Failed to execute 'structuredClone'
}

image

1.2. JSON.parse(JSON.stringify())

1.2.1. 支援的型別
  • 數字
  • 字串
  • 布林值
  • 陣列
  • 普通物件
1.2.2. 不支援的型別
  • Date、Map、Set、RegExp、Function、undefined、symbol、Infinity、NaN、迴圈引用...

JSON.stringify 詳細資訊可以看下下面的文章

你需要了解的JSON.stringify()

1.2.3. 示例
JSON.parse(JSON.stringify({
  a: null,
  b: undefined,
  c: NaN,
  d: Infinity,
  e: () => ({}),
  f: new Map(),
  g: new Set(),
  h: Symbol('a'),
  i: Infinity
}))

// 返回值

{
  "a": null,
  "c": null,
  "d": null,
  "f": {},
  "g": {},
  "i": null
}

image

2. 迴圈引用

2.1. structuredClone

可以正確處理物件中的迴圈引用

2.2. JSON.parse(JSON.stringify)

如果物件中存在迴圈引用,呼叫 JSON.stringify 會丟擲錯誤,導致克隆失敗

image

3. 效能方面

3.1. structuredClone

通常在處理複雜物件時效能更優,特別是包含大量非 JSON 相容型別的資料時,因為它是為深度克隆設計的原生方法,內部最佳化了許多複雜場景

3.2. JSON.parse(JSON.stringify)

在處理簡單的、JSON 相容的資料結構時可能效能較好,但在處理複雜物件或非 JSON 相容型別時效率低下

4. 瀏覽器相容

4.1. structuredClone

是一種較新的 API,在某些較舊的瀏覽器中不被支援

image

image

4.2. JSON.parse(JSON.stringify)

在現代瀏覽器和較舊的瀏覽器中都有廣泛支援

image

三、總結

  • structuredClone 提供了更廣泛的資料型別支援和對迴圈引用的處理能力,適用於複雜場景
  • JSON.parse(JSON.stringify) 適合處理簡單、JSON 相容的資料結構,但在處理複雜資料型別或迴圈引用時有侷限性
  • 兩者都有限制,克隆的時候需要關注下克隆物件的資料型別再做選擇

參考

  • structuredClone
  • 你需要了解的JSON.stringify()

相關文章