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

参考

相关推荐
长风清留扬26 分钟前
小程序毕业设计-音乐播放器+源码(可播放)下载即用
javascript·小程序·毕业设计·课程设计·毕设·音乐播放器
m0_7482478040 分钟前
Flutter Intl包使用指南:实现国际化和本地化
前端·javascript·flutter
ZJ_.1 小时前
WPSJS:让 WPS 办公与 JavaScript 完美联动
开发语言·前端·javascript·vscode·ecmascript·wps
joan_852 小时前
layui表格templet图片渲染--模板字符串和字符串拼接
前端·javascript·layui
还是大剑师兰特2 小时前
什么是尾调用,使用尾调用有什么好处?
javascript·大剑师·尾调用
Watermelo6172 小时前
详解js柯里化原理及用法,探究柯里化在Redux Selector 的场景模拟、构建复杂的数据流管道、优化深度嵌套函数中的精妙应用
开发语言·前端·javascript·算法·数据挖掘·数据分析·ecmascript
一个处女座的程序猿O(∩_∩)O5 小时前
小型 Vue 项目,该不该用 Pinia 、Vuex呢?
前端·javascript·vue.js
燃先生._.11 小时前
Day-03 Vue(生命周期、生命周期钩子八个函数、工程化开发和脚手架、组件化开发、根组件、局部注册和全局注册的步骤)
前端·javascript·vue.js
高山我梦口香糖12 小时前
[react]searchParams转普通对象
开发语言·前端·javascript