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. 语法
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对象MapSetArrayBufferTypedArraysBlobFileImageDataMessagePortnull、undefinedNaN、Infinity、-Infinity- 循环引用
1.1.2. 不支持的类型
- 函数
symbolWeakMapWeakSetHTMLElement
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 详细信息可以看下下面的文章
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兼容的数据结构,但在处理复杂数据类型或循环引用时有局限性- 两者都有限制,克隆的时候需要关注下克隆对象的数据类型再做选择
参考
JavaScript 中 structuredClone 和 JSON.parse(JSON.stringify()) 克隆对象的区别的更多相关文章
- javascript 数组和对象的浅复制和深度复制 assign/slice/concat/JSON.parse(JSON.stringify())
javascript 数组和对象的浅度复制和深度复制在平常我们用 ‘=’来用一个变量引用一个数组或对象,这里是‘引用’而不是复制下面我们看一个例子引用和复制是什么概念 var arr=[1,2,3,' ...
- 关于JSON.parse(JSON.stringify(obj))实现深拷贝应该注意的坑
JSON.parse(JSON.stringify(obj))我们一般用来深拷贝,其过程说白了 就是利用JSON.stringify 将js对象序列化(JSON字符串),再使用JSON.parse来反 ...
- 实现深拷贝还在用JSON.parse(JSON.stringify(obj))?带你用JS实现一个完整版深拷贝函数
使用JavaScript实现深拷贝 1.JSON序列化实现深拷贝 在JS中,想要对某一个对象(引用类型)进行一次简单的深拷贝,可以使用JSON提供给我们的两个方法. JSON.stringfy():可 ...
- JSON.parse JSON.stringify
JSON.stringify() undefined 值.函数或者XML值会被忽略 数组当中含有 undefined值,函数或XML值,该数组中的这些值将会被当成 null 正则对象会被转成空对象 J ...
- JSON.parse(JSON.stringify()) 实现对对象的深拷贝
JSON.parse(JSON.stringify(obj))我们一般用来深拷贝,其过程说白了 就是利用JSON.stringify 将js对象序列化(JSON字符串),再使用JSON.parse来反 ...
- JSON.parse() JSON.stringify() eval() jQuery.parseJSON() 的区别
http://www.jb51.net/article/81880.htm : jQuery.parseJSON(jsonString) : 将格式完好的JSON字符串转为与之对应的Java ...
- 使用JSON.parse(),JSON.stringify()实现对对象的深拷贝
根据不包含引用对象的普通数组深拷贝得到启发,不拷贝引用对象,拷贝一个字符串会新辟一个新的存储地址,这样就切断了引用对象的指针联系. 测试例子: var test={ a:"ss", ...
- JSON.parse(JSON.stringify(obj))
JSON.parse(JSON.stringify(obj)实现数组的深拷贝 利用JSON.stringify 将js对象序列化(JSON字符串),再使用JSON.parse来反序列化(还原)js对象
- 【Immutable】拷贝与JSON.parse(JSON.stringify()),深度比较相等与underscore.isEqual(),性能比较
样本:1MB的JSON文件,引入后生成500份的一个数组: 结果如下: 拷贝性能: JSON.parse(JSON.stringify()) 的方法:2523.55517578125ms immuta ...
- this.treeData = JSON.parse(JSON.stringify(this.d)) 树的序列化反序列化
this.treeData = JSON.parse(JSON.stringify(this.d))
随机推荐
- Mac mysql 5.7启动报错,解决之道 The server quit without updating PID file
导读 晚上捣鼓数据库的时候,将mysql服务停止下,然后就死活启动不起来,这下可把我急坏了,自己数据库上有好多自己的个人项目,错误信息如下 ERROR! The server quit without ...
- SpringBoot定义异步任务类需要获取结果
注意点: 要把异步任务封装到类里面,不能直接写到Controller 增加Future<String>返回结果AsyncResult<String>("task执行完 ...
- @Autowired和@Resource有哪些区别
一.注解的作用 @Autowired和@Resource都是用来实现Bean的自动注入功能. 二.@Autowired和@Resource的区别 1.所属的包不同 @Autowired是Spring的 ...
- Maven Helper插件——实现一键Maven依赖冲突问题
业余在一个SpringBoot项目集成Swagger2时,启动过程一直出现以下报错信息-- An attempt was made to call a method that does not exi ...
- Solo 开发者周刊 (第4期):什么样的新科技,能提高生活效率?
这里会整合 Solo 社区每周推广内容.产品模块或活动投稿,每周五发布.在这期周刊中,我们将深入探讨开源软件产品的开发旅程,分享来自一线独立开发者的经验和见解.本杂志开源,欢迎投稿. 好文推荐 AI生 ...
- 深入探究 Golang 反射:功能与原理及应用
Hi 亲爱的朋友们,我是 k 哥.今天,咱们来一同探讨下 Golang 反射. Go 出于通用性的考量,提供了反射这一功能.借助反射功能,我们可以实现通用性更强的函数,传入任意的参数,在函数内通过反射 ...
- 关于使用c++制作蓝牙连接,Windows版本
1 #define _CRT_SECURE_NO_WARNINGS 2 #pragma warning(disable : 4995) 3 #include <iostream> 4 #i ...
- git篇-- Git在项目实操中常见的使用命令--02
Git是现代软件开发中不可或缺的版本控制工具.它能帮助开发者跟踪项目的所有变更,并与团队成员高效协作.本文将介绍一些在项目实操中常见的Git命令,帮助你更好地管理代码. 1. 初始化和配置 初始化仓库 ...
- 认识netty的基本组件
Java NIO VS Netty 有了 Java NIO,而且 Netty 也是基于 Java NIO 实现,那么为什么不能直接用 Java NIO 来实现网络通信模块呢? 接下来我就给大家解释一下 ...
- Jmeter强制结束线程
例子:正常的线程是执行2次请求 1.需要实现结果 执行请求1后,判断test1=100,强制结束线程 执行请求1后,判断test1 != 100,继续执行请求2 2. 线程组改造 在请求1后面增加[i ...