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

参考

JavaScript 中 structuredClone 和 JSON.parse(JSON.stringify()) 克隆对象的区别的更多相关文章

  1. javascript 数组和对象的浅复制和深度复制 assign/slice/concat/JSON.parse(JSON.stringify())

    javascript 数组和对象的浅度复制和深度复制在平常我们用 ‘=’来用一个变量引用一个数组或对象,这里是‘引用’而不是复制下面我们看一个例子引用和复制是什么概念 var arr=[1,2,3,' ...

  2. 关于JSON.parse(JSON.stringify(obj))实现深拷贝应该注意的坑

    JSON.parse(JSON.stringify(obj))我们一般用来深拷贝,其过程说白了 就是利用JSON.stringify 将js对象序列化(JSON字符串),再使用JSON.parse来反 ...

  3. 实现深拷贝还在用JSON.parse(JSON.stringify(obj))?带你用JS实现一个完整版深拷贝函数

    使用JavaScript实现深拷贝 1.JSON序列化实现深拷贝 在JS中,想要对某一个对象(引用类型)进行一次简单的深拷贝,可以使用JSON提供给我们的两个方法. JSON.stringfy():可 ...

  4. JSON.parse JSON.stringify

    JSON.stringify() undefined 值.函数或者XML值会被忽略 数组当中含有 undefined值,函数或XML值,该数组中的这些值将会被当成 null 正则对象会被转成空对象 J ...

  5. JSON.parse(JSON.stringify()) 实现对对象的深拷贝

    JSON.parse(JSON.stringify(obj))我们一般用来深拷贝,其过程说白了 就是利用JSON.stringify 将js对象序列化(JSON字符串),再使用JSON.parse来反 ...

  6. JSON.parse() JSON.stringify() eval() jQuery.parseJSON() 的区别

    http://www.jb51.net/article/81880.htm    :   jQuery.parseJSON(jsonString) : 将格式完好的JSON字符串转为与之对应的Java ...

  7. 使用JSON.parse(),JSON.stringify()实现对对象的深拷贝

    根据不包含引用对象的普通数组深拷贝得到启发,不拷贝引用对象,拷贝一个字符串会新辟一个新的存储地址,这样就切断了引用对象的指针联系. 测试例子: var test={ a:"ss", ...

  8. JSON.parse(JSON.stringify(obj))

    JSON.parse(JSON.stringify(obj)实现数组的深拷贝 利用JSON.stringify 将js对象序列化(JSON字符串),再使用JSON.parse来反序列化(还原)js对象

  9. 【Immutable】拷贝与JSON.parse(JSON.stringify()),深度比较相等与underscore.isEqual(),性能比较

    样本:1MB的JSON文件,引入后生成500份的一个数组: 结果如下: 拷贝性能: JSON.parse(JSON.stringify()) 的方法:2523.55517578125ms immuta ...

  10. this.treeData = JSON.parse(JSON.stringify(this.d)) 树的序列化反序列化

    this.treeData = JSON.parse(JSON.stringify(this.d))

随机推荐

  1. 基于EF Core存储的国际化服务

    前言 .NET 官方有一个用来管理国际化资源的扩展包Microsoft.Extensions.Localization,ASP.NET Core也用这个来实现国际化功能.但是这个包的翻译数据是使用re ...

  2. Java-记住上一次访问时间案例

    记住上一次访问时间 1.需求: 1.访问一个Servlet,如果是第一次访问,则提示:您好,欢迎您首次访问 2.如果不是第一次访问,则提示:欢迎回来,您上次访问的时间为:显示字符串 2.分析 1.可以 ...

  3. Redis巡检检查 redis-check-aof

    一.AOF1.AOF  是什么以日志的形式来记录每个写操作,将Redis执行过的所有写指令记录下来(读操作不记录),只许追加文件但不可以改写文件,Redis启动之初会读取该文件重新构建数据,换言之,R ...

  4. 类、事件与对象---Dad&Mom简单练习

    目的: 模拟一个家庭日常发生的场景:妈妈做好饭,说:"开饭了!",这是爸爸听到了妈妈的喊话就立马动身开始饭吃.而儿子此时正在打游戏,于是他就说:"等我打完这把游戏再吃!& ...

  5. 当项目中使用到缓存,我们是选择 Redis 还是 Memcached ,为什么?

    举一些场景: 一.比如实现一个简单的日志收集功能或发送大量短信.邮件的功能,实现方式是先将数据收集到队列中,然后有一个定时任务去消耗队列,处理该做的事情. 直接使用 Redis 的 lpush,rpo ...

  6. [oeasy]python0093_电子游戏起源_视频游戏_达特茅斯_Basic_家酿俱乐部

    编码进化 回忆上次内容 Ed Robert 的 创业之路 从 售卖 diy 组装配件 到进军 计算器市场 最后 发布 牛郎星8800 intel 8080 的出现 让 人人都有 自己的 个人电脑 Bi ...

  7. 格式输出函数printf()详解_C语言

    printf函数称为格式输出函数,其关键字最末一个字母f即为"格式"(format)之意.其功能是按用户指定的格式,把指定的数据显示到显示器屏幕上. printf函数调用的一般形式 ...

  8. ngnix简介和基础

    一.Nginx简介 Nginx 是一个高性能的HTTP和反向代理服务器,同时也是一个IMAP/POP3/SMTP代理服务器 是一个模块化软件 [1].安装nginx 使用源码包编译安装 cd /opt ...

  9. RS485总线防雷保护方案(转)

    RS485作为最为最常用的电表通讯方式之一.日常生活中雷电和静电干扰已经成为485通信总线在实际工程经常遇到的问题.故如何对芯片以及总线进行有效的保护,是摆在每一个使用者面前的一个问题.在这里,我们主 ...

  10. python获取引用对象的个数

    python获取引用对象的个数 使用sys.getrefcount()来获取当前对象被引用了多少次,返回的结果比实际大1 import sys class A: pass a = A() #创建实例对 ...