動態

詳情 返回 返回

JS 中 structuredClone 和 JSON.parse(JSON.stringify()) 克隆對象的區別 - 動態 詳情

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);

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);

二、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);

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'
}

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
}

2. 循環引用

2.1. structuredClone

可以正確處理對象中的循環引用

2.2. JSON.parse(JSON.stringify)

如果對象中存在循環引用,調用 JSON.stringify 會拋出錯誤,導致克隆失敗

3. 性能方面

3.1. structuredClone

通常在處理複雜對象時性能更優,特別是包含大量非 JSON 兼容類型的數據時,因為它是為深度克隆設計的原生方法,內部優化了許多複雜場景

3.2. JSON.parse(JSON.stringify)

在處理簡單的、JSON 兼容的數據結構時可能性能較好,但在處理複雜對象或非 JSON 兼容類型時效率低下

4. 瀏覽器兼容

4.1. structuredClone

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

4.2. JSON.parse(JSON.stringify)

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

三、總結

  • structuredClone 提供了更廣泛的數據類型支持和對循環引用的處理能力,適用於複雜場景
  • JSON.parse(JSON.stringify) 適合處理簡單、JSON 兼容的數據結構,但在處理複雜數據類型或循環引用時有侷限性
  • 兩者都有限制,克隆的時候需要關注下克隆對象的數據類型再做選擇

參考

  • 【structuredClone】
  • 【你需要了解的JSON.stringify()】
user avatar grewer 頭像 linx 頭像 tonyyoung 頭像 limingxin 頭像 honwhy 頭像 feipeng123s 頭像 shenyongweiwudemaozi 頭像 bill_5bac65cc7963b 頭像
點贊 8 用戶, 點贊了這篇動態!
點贊

Add a new 評論

Some HTML is okay.