structuredClone 与 JSON.parse(JSON.stringify()) 方法
概述 两者都用于深拷贝对象,但存在重要差异:
- structuredClone() 现代浏览器 API,专为克隆设计 优势: ✅ 支持循环引用
javascript
const obj = { name: "John" };
obj.self = obj;
const cloned = structuredClone(obj); // 正常工作
✅ 支持更多数据类型:
javascript
Map、Set
Date(保持对象类型)
RegExp(保持对象类型)
ArrayBuffer、TypedArray
Blob、File
Error 类型(部分浏览器)
✅ 保持原型链(部分对象类型)
✅ 更高效(专门优化的算法)
限制: ❌ 不支持函数
❌ 不支持 DOM 节点
❌ 不支持 Symbol 属性
❌ IE 不支持
- JSON.parse(JSON.stringify()) 传统方法,通过 JSON 序列化实现
优势: ✅ 广泛兼容(包括旧浏览器)
✅ 简单易用
限制: ❌ 不支持循环引用
javascript
javascript
const obj = { name: "John" };
obj.self = obj;
const cloned = JSON.parse(JSON.stringify(obj)); // 报错
❌ 数据类型丢失严重:
javascript
Date → 字符串
Map/Set → 空对象 {}
RegExp → 空对象 {}
Function → 被移除
undefined → 被移除
NaN/Infinity → null
Symbol → 被移除
❌ 原型链丢失(全部变为普通对象)
性能对比
javascript
// 基准测试示例
const obj = { /* 大型复杂对象 */ };
// structuredClone 通常更快
console.time('structuredClone');
structuredClone(obj);
console.timeEnd('structuredClone');
// JSON 方法较慢
console.time('JSON方法');
JSON.parse(JSON.stringify(obj));
console.timeEnd('JSON方法');
const original = {
date: new Date(),
set: new Set([1, 2, 3]),
map: new Map([['a', 1]]),
regex: /test/gi,
fn: () => console.log('test'),
undef: undefined,
nan: NaN
};
// structuredClone
const clone1 = structuredClone(original);
console.log(clone1.date instanceof Date); // true
console.log(clone1.set instanceof Set); // true
// clone1.fn === undefined
// JSON 方法
const clone2 = JSON.parse(JSON.stringify(original));
console.log(typeof clone2.date); // "string"
console.log(clone2.set); // {}
console.log(clone2.fn); // undefined
选择建议 使用 structuredClone 当: 需要支持循环引用
需要保持特殊对象类型(Date、Map、Set等)
在现代浏览器/Node.js(≥17)环境中
处理复杂对象结构
使用 JSON 方法 当: 只需要简单的数据对象(无特殊类型)
不需要支持循环引用
需要兼容旧环境
明确知道对象只包含 JSON 安全的数据
其他替代方案:
javascript
// 第三方库
import cloneDeep from 'lodash/cloneDeep';
// 自定义深拷贝函数
function deepClone(obj, hash = new WeakMap()) {
// 处理循环引用和复杂类型
}
总结表格
| 特性 | structuredClone |
JSON.parse(JSON.stringify()) |
|---|---|---|
| 循环引用 | ✅ 支持 | ❌ 报错(抛出 TypeError) |
| Date 对象 | ✅ 保持 Date 类型 | ❌ 转为 ISO 格式字符串 |
| Map/Set | ✅ 保持 Map/Set 类型 | ❌ 转为空对象 {} |
| 函数 | ❌ 不支持(抛出 DOMException) | ❌ 被移除 |
| undefined | ✅ 支持 | ❌ 被移除 |
| Symbol | ❌ 不支持(抛出 DOMException) | ❌ 被移除 |
| 原型链 | ✅ 部分保持(仅限可克隆对象) | ❌ 完全丢失 |
| 性能 | ✅ 较优(原生实现) | ❌ 较慢(需序列化和解析) |
| 兼容性 | 现代浏览器(Chrome 98+、Firefox 94+) | 所有浏览器(包括旧版 IE) |
补充说明:
-
循环引用示例:
javascriptconst obj = { name: "Alice" }; obj.self = obj; structuredClone(obj); // 正常克隆 JSON.stringify(obj); // 报错:Converting circular structure to JSON -
Date 对象处理差异:
javascriptconst date = new Date(); structuredClone(date) instanceof Date; // true JSON.parse(JSON.stringify(date)) instanceof Date; // false -
Map/Set 的特殊处理:
javascriptconst map = new Map([["key", "value"]]); structuredClone(map) instanceof Map; // true JSON.parse(JSON.stringify(map)); // {} -
性能对比场景:
- 对于 1MB 大小的对象:
structuredClone耗时约 15msJSON方法耗时约 35ms(含序列化和解析)
- 对于 1MB 大小的对象:
-
原型链保留范围:
structuredClone会保留内置对象(如 Array)的原型链- 自定义类的原型链会被扁平化为普通对象 推荐:在现代应用中使用 structuredClone(),为更复杂的场景准备备选方案。
