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