JavaScript 中 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. 语法

javascript 复制代码
structuredClone(value)
structuredClone(value, { transfer })

2.2. 参数

  • value:被克隆的对象
  • transfer:可转移的数组

2.3. 返回值

返回值是原始值的深拷贝

2.4.

如果输入值的任一部分不可序列化,则抛出 DataCloneError 异常

3. 用法

3.1. 普通用法

javascript 复制代码
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 是一个可转移对象的数组,里面的值并没有被克隆,而是被转移到被拷贝对象上

javascript 复制代码
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. 示例
javascript 复制代码
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);
javascript 复制代码
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. 示例
javascript 复制代码
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 兼容的数据结构,但在处理复杂数据类型或循环引用时有局限性
  • 两者都有限制,克隆的时候需要关注下克隆对象的数据类型再做选择

参考

相关推荐
烬羽10 小时前
React Router v7 完全指南:一个 Demo 吃透前端路由
javascript·react.js·前端框架
烬羽10 小时前
从"整个页面刷新"到"丝滑切换":手写一个 HashRouter 彻底搞懂前端路由
javascript·前端框架·全栈
用户9385156350710 小时前
从零理解 React Router v6:每一个 API 都是怎么工作的
前端·javascript·全栈
kyriewen13 小时前
别再这样写条件渲染了——你的React组件里藏着这5种定时炸弹
前端·javascript·react.js
梦想CAD控件14 小时前
网页端CAD的图形选择、编辑与夹点操作教程
前端·javascript·node.js
月月大王的3D日记14 小时前
Three.js 入门系列(8):六种光源全解析 —— 关灯了,开光!
前端·javascript
自然 醒15 小时前
v-tooltip自定义指令封装
前端·javascript·vue.js
其美杰布-富贵-李17 小时前
第 10 篇:灯光与阴影
javascript·three.js
小高00718 小时前
🔥🔥🔥TypeScript 7 正式版来了:别只看 10 倍速度,这 4 个迁移坑更值得注意
前端·javascript·面试
di24k24k19 小时前
多个 el-form 共用同一 ref 导致表单校验部分失效
前端·javascript·vue.js·elementui