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))
随机推荐
- SpringBoot 解决跨域问题
今天遇到一个很神奇的问题,之前写的项目,后端跨域都处理好的,按部就班使用原来的方式,前后端都开发完之后,部署本地后,跨域没起效,一脸懵逼,然后使用公司另外一个同事的跨域解决方案,具体我也没深入研究到底 ...
- go语言的基础语法
字符串数组 package main import ( "fmt" ) func main() { var str string str = "hello world&q ...
- [oeasy]python0045_四种进制_binary_octal_decimal_hexadecimal
四种进制 回忆上次内容 上次研究了 通过 八进制数值 转义 \ooo 把(ooo)8进制对应的ascii字符输出 转义序列 \n.\t 是 转义序列 \xhh 也是 转义序列 \ooo 还是 转义序列 ...
- [oeasy]python0041_teletype历史_博多码_shift_capslock_字符数字切换_gear
teletypewriter 历史 回忆上次内容 上次见到了一个真的机械打字机 感受到了蒸汽朋克的时代背景 上上次区分了一些概念 terminal终端,电脑连线最终的端点 TeleTYpewriter ...
- oeasy教您玩转vim - 41 - # 各寄存器
各寄存器 回忆上节课内容 上次是复制粘贴 y就是把东西yank到寄存器里,就是复制 d就是把东西delete到寄存器里,就是剪切 yank也可以配合motion 不管是yank.delete都是把 ...
- [oeasy]python0015_十六进制_hexadecimal_字节形态_hex函数
十六进制(hexadecimal) 回忆上次内容 上次数制可以转化 bin(n)可以把数字转化为 2进制 binary 接收一个整数(int) 得到一个二进制数形式的字符串 编辑 数字在 ...
- 数组的创建-数组-C
数组内存是连续的 数组是一个整体,它的内存是连续的:也就是说,数组元素之间是相互挨着的,彼此之间没有一点点缝隙.下图演示了int a[4];在内存中的存储情形: 「数组内存是连续的」这一点很重要,所以 ...
- 【Spring】05 注解开发
环境搭建 配置ApplicationContext.xml容器文件[半注解实现] <?xml version="1.0" encoding="UTF-8" ...
- 【郝斌C ST】 指针入门
#include <stdio.h> int main() { printf("Hello, World!\n"); int i = 3; int * p = & ...
- python数据分析与可视化基础
一.数据分析介绍:1.数据分析含义:数据分析是指用适当的统计分析方法对收集来的大量数据进行分析,将它们加以汇总和理解并消化,以求最大化地开发数据的功能,发挥数据的作用.数据分析是为了提取有用信息和形成 ...