javascript深度克隆需递归处理各类对象:先用weakmap解决循环引用,再用object.prototype.tostring精准判型,分别构造date、regexp、map、set等特殊类型,最后遍历可枚举属性递归复制。

JavaScript中用递归函数实现复杂对象的深度克隆,核心是逐层遍历对象或数组的每个属性,对引用类型(对象、数组、Date、RegExp等)递归处理,对基本类型直接赋值。关键要处理循环引用、特殊对象(如Date、RegExp、Map、Set)和不可枚举属性。
基础递归逻辑:识别类型并分支处理
递归函数需先判断当前值的类型:如果是 null 或原始类型(string、number、boolean、symbol、bigint、undefined),直接返回;如果是 Date 或 RegExp,新建对应实例;如果是数组或普通对象,则递归复制其每个可枚举属性。
- 用 Object.prototype.toString.call(val) 精准判断类型,比
typeof更可靠 - 对数组用
Array.isArray()单独判断,避免被当作普通对象处理 - 遍历对象时用
Object.keys()或for...in配合hasOwnProperty,确保只处理自身可枚举属性
处理循环引用:用 WeakMap 缓存已克隆的对象
当对象存在自引用或相互引用时,不加控制的递归会导致栈溢出。解决方案是维护一个 WeakMap,以原对象为键、克隆后对象为值,在每次进入递归前先查缓存。
Java JDK 25 来自 OpenJDK 官方归档,版本为 JDK 25,本条下载地址已指向官方 Windows x64 zip 安装包直链,适合调试旧项目或兼容旧版 Java 运行环境。
- WeakMap 键必须是对象,且不影响垃圾回收,适合做映射缓存
- 若当前对象已在 WeakMap 中,直接返回缓存值,跳过重复克隆
- 新建克隆对象后立即存入 WeakMap,再递归填充属性
支持常见内置类型:Date、RegExp、Map、Set
除了普通对象和数组,实际项目中常遇到 Date、RegExp、Map、Set 等。它们不能通过 {...obj} 或 Object.assign 正确克隆,需单独构造:
-
Date →
new Date(obj.getTime()) -
RegExp →
new RegExp(obj.source, obj.flags) -
Map → 新建 Map,遍历原 Map 的
entries(),递归克隆 key 和 value -
Set → 新建 Set,遍历原 Set 的
values(),递归克隆每个元素
完整示例(不含 Proxy 和 ArrayBuffer)
以下是一个兼顾健壮性与可读性的递归深克隆函数:
function deepClone(obj, cache = new WeakMap()) {
if (obj === null || typeof obj !== 'object') return obj;
if (cache.has(obj)) return cache.get(obj);
let cloned;
const typeStr = Object.prototype.toString.call(obj);
if (typeStr === '[object Date]') {
cloned = new Date(obj.getTime());
} else if (typeStr === '[object RegExp]') {
cloned = new RegExp(obj.source, obj.flags);
} else if (Array.isArray(obj)) {
cloned = [];
} else if (typeStr === '[object Map]') {
cloned = new Map();
} else if (typeStr === '[object Set]') {
cloned = new Set();
} else {
cloned = {};
}
cache.set(obj, cloned);
if (Array.isArray(obj)) {
obj.forEach((item, i) => {
cloned[i] = deepClone(item, cache);
});
} else if (obj instanceof Map) {
obj.forEach((value, key) => {
cloned.set(deepClone(key, cache), deepClone(value, cache));
});
} else if (obj instanceof Set) {
obj.forEach(item => {
cloned.add(deepClone(item, cache));
});
} else {
for (const key of Object.keys(obj)) {
cloned[key] = deepClone(obj[key], cache);
}
}
return cloned;
}
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










