在JavaScript中,深度复制复杂对象一直是一个常见的需求。传统的解决方案如对象扩展运算符、JSON.parse与JSON.stringify组合,以及第三方库(例如Lodash的_.cloneDeep)都存在局限性。而现在,JavaScript运行时内置了一个名为structuredClone
的方法,它可以有效地解决这些问题。
structuredClone 的功能特性
- 深度复制:
structuredClone
能够递归地复制对象和数组,确保原始对象与其副本之间的引用独立。
const calendarEvent = {
title: "Builder.io Conf",
date: new Date(123),
attendees: ["Steve"]
};
const copied = structuredClone(calendarEvent);
copied.attendees.push("Bob"); // 不会影响原对象
-
广泛类型支持:不仅能复制常见JS类型(包括Date, Set, Map, Error, RegExp, ArrayBuffer等),还能处理Blob, File, ImageData等多种Web API类型,并且可以处理循环引用。
-
无限层级嵌套:无论嵌套结构多么复杂,都能正确复制。
为什么不用其他方法?
对象扩展运算符 {…}
当需要浅层复制时,对象扩展运算符是很好的选择。
const simpleEvent = {
title: "Builder.io Conf",
};
// 浅层复制,适用于无嵌套对象或数组的情况
const shallowCopy = {...simpleEvent};
然而,当面对包含嵌套对象或数组的对象时,它只会创建一层新的引用,扩展运算符无法完成深度复制:
const calendarEvent = {
title: "Builder.io Conf",
date: new Date(123),
attendees: ["Steve"]
};
const shallowCopy = {...calendarEvent};
// 🚩 问题出现 - 修改副本同时也影响了原始对象
shallowCopy.attendees.push("Bob");
// 🚩 同样问题 - 更新副本的同时也更新了原始对象的时间
shallowCopy.date.setTime(456);
JSON.parse(JSON.stringify(x))
使用这种方法虽然性能不错,但它仅能处理基础对象、数组和原始类型。对于Date对象会转换为字符串表示,而对于Set、Map等类型则可能无法预期地转为空对象,甚至忽略undefined和函数等属性。此外,它不能处理循环引用并会抛出错误。
const calendarEvent = {
title: "Builder.io Conf",
date: new Date(123),
attendees: ["Steve"]
};
// 使用JSON.stringify进行序列化,然后JSON.parse解析回对象
const problematicCopy = JSON.parse(JSON.stringify(calendarEvent));
// 输出结果:
// {
// "title": "Builder.io Conf",
// "date": "1970-01-01T00:00:00.123Z",
// "attendees": ["Steve"]
// }
Lodash 的 _.cloneDeep 方法
Lodash的_.cloneDeep方法确实能够满足深度复制的需求,然而其大小约为17.4KB(minified)、5.3KB(gzipped)。考虑到浏览器已经内置了structuredClone方法,额外引入一个大型库显得没有必要。
structuredClone 不支持的内容
-
函数:尝试复制函数会导致
DataCloneError
异常。 -
DOM节点:同样会引发
DataCloneError
异常。 -
属性描述符、setter 和 getter:不会复制这些元数据属性。getter属性的值会被复制,但getter函数本身不会被复制。
-
对象原型:不遍历或复制原型链,因此克隆后的对象不再属于原始构造函数的实例,尽管其属性会被复制。
支持的类型一览
structuredClone
支持以下类型:
-
JS 内置类型:Array、ArrayBuffer、Boolean、DataView、Date、特定Error类型、Map、纯对象、原始类型(除symbol外)、RegExp、Set、TypedArray
-
错误类型:Error、EvalError、RangeError、ReferenceError、SyntaxError、TypeError、URIError
-
Web/API 类型:AudioData、Blob、CryptoKey、DOMException、DOMMatrix、DOMMatrixReadOnly、DOMPoint、DomQuad、DomRect、File、FileList、FileSystemDirectoryHandle、FileSystemFileHandle、FileSystemHandle、ImageBitmap、ImageData、RTCCertificate、VideoFrame
浏览器兼容性
structuredClone
已在所有主流浏览器及Node.js、Deno环境中得到支持。需要注意的是,在Web Worker中的支持相对有限。
参考链接:MDN ;Deep Cloning Objects in JavaScript, the Modern Way