structuredclone()是现代环境首选深拷贝方案,支持date、regexp、map、set、循环引用等,但不支持function、undefined、symbol;旧环境可用lodash clonedeep或手写递归(配合weakmap防循环)。

JavaScript 中直接用 JSON.parse(JSON.stringify(obj)) 无法正确复制 Date 对象(会变成字符串),也无法处理 RegExp、Map、Set、undefined、function、BigInt 等特殊类型。要可靠地深拷贝含 Date 的对象,需手动处理这些类型或使用成熟方案。
用 structuredClone(现代浏览器推荐)
structuredClone 是原生 API,支持 Date、RegExp、Map、Set、ArrayBuffer、TypedArray 等,但不支持 function、undefined、Symbol、BigInt(部分环境已支持 BigInt)。
- ✅ 支持
Date、RegExp、循环引用(自动处理) - ❌ 不支持
function、undefined、Symbol(会丢失或报错) - ⚠️ 注意:Node.js 17.0+ 和主流浏览器(Chrome 98+、Firefox 94+、Safari 15.4+)才支持
用法:
const original = { time: new Date('2023-01-01'), re: /abc/g };
const copy = structuredClone(original); // Date 和 RegExp 都被正确复制
console.log(copy.time instanceof Date); // true
console.log(copy.re instanceof RegExp); // true
手写兼容性深拷贝(支持 Date 等常用类型)
若需兼容旧环境或控制行为(如跳过函数、保留 undefined),可自定义递归拷贝函数,对 Date、RegExp、Map、Set 等单独处理:
- 遇到
Date→new Date(date.getTime())或new Date(date.toString()) - 遇到
RegExp→new RegExp(regexp.source, regexp.flags) - 遇到
Map→ 新建Map,递归拷贝 key/value - 遇到
Set→ 新建Set,递归拷贝每个值 - 普通对象/数组 → 递归遍历属性/元素
- 基础类型(string/number/boolean/null)→ 直接返回
示例片段:
function deepClone(obj, seen = new WeakMap()) {
if (obj === null || typeof obj !== 'object') return obj;
if (seen.has(obj)) return seen.get(obj);
let copy;
if (obj instanceof Date) {
copy = new Date(obj.getTime());
} else if (obj instanceof RegExp) {
copy = new RegExp(obj.source, obj.flags);
} else if (obj instanceof Map) {
copy = new Map();
obj.forEach((value, key) => {
copy.set(deepClone(key, seen), deepClone(value, seen));
});
} else if (obj instanceof Set) {
copy = new Set();
obj.forEach(item => copy.add(deepClone(item, seen)));
} else {
copy = Array.isArray(obj) ? [] : {};
seen.set(obj, copy);
for (const key in obj) {
if (Object.prototype.hasOwnProperty.call(obj, key)) {
copy[key] = deepClone(obj[key], seen);
}
}
}
return copy;
}
用 Lodash 的 cloneDeep(工程首选)
在真实项目中,推荐直接使用 Lodash 的 cloneDeep,它已完备处理:Date、RegExp、Map、Set、ArrayBuffer、TypedArray、Promise、URL、Error、循环引用等,且兼容性好、经过大量验证。
- 安装:
npm install lodash.clonedeep - 使用:
import cloneDeep from 'lodash.clonedeep';或const { cloneDeep } = require('lodash'); - 支持自定义克隆逻辑(通过
customizer参数)
示例:
import cloneDeep from 'lodash.clonedeep';
const data = {
created: new Date(),
pattern: /test/gi,
meta: new Map([['id', 123]]),
tags: new Set(['js', 'deep'])
};
const cloned = cloneDeep(data);
console.log(cloned.created instanceof Date); // true
注意事项和常见陷阱
无论用哪种方式,都需注意:
-
function和undefined在大多数深拷贝中会被忽略或丢失(structuredClone报错,cloneDeep跳过) -
Symbol键不会被JSON方法或多数递归实现复制(cloneDeep默认也不处理,需 customizer) - 循环引用必须显式检测(WeakMap 缓存原始对象),否则栈溢出
- 原型链上的属性不会被拷贝(深拷贝只处理自有可枚举属性)
- 性能敏感场景慎用深层嵌套大对象的深拷贝,考虑是否真需要“全量复制”
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











