javascript递归深拷贝核心是类型判断与逐层重建,基础版仅处理对象和数组,增强版用weakmap解决循环引用,还可扩展支持date、regexp、map、set等类型。

JavaScript 中用递归函数实现深拷贝对象,核心是判断数据类型、逐层遍历并重建结构。它能处理普通对象、数组,也能应对嵌套对象和数组,但要注意循环引用、特殊类型(如 Date、RegExp、Function)等边界情况。
基础递归深拷贝(支持对象和数组)
最简版本只处理 object 和 array,其他类型(字符串、数字、布尔、null)直接返回:
function deepClone(obj) {
// 处理 null 和非对象类型(包括原始值)
if (obj === null || typeof obj !== 'object') return obj;
// 区分数组和普通对象
const result = Array.isArray(obj) ? [] : {};
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
// 递归拷贝每个属性值
result[key] = deepClone(obj[key]);
}
}
return result;
}
✅ 优点:逻辑清晰,适合理解递归原理
⚠️ 缺点:不处理 Date、RegExp、Map、Set、Symbol、函数、undefined,且遇到循环引用会爆栈
增强版:避免循环引用(关键改进)
对象中若存在循环引用(比如 a.b = a),递归会无限深入。解决方法是用 WeakMap 记录已拷贝过的源对象及其对应的新对象:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
function deepClone(obj, map = new WeakMap()) {
if (obj === null || typeof obj !== 'object') return obj;
// 检查是否已拷贝过该对象
if (map.has(obj)) return map.get(obj);
const result = Array.isArray(obj) ? [] : {};
// 立即存入 map,防止后续递归时重复处理
map.set(obj, result);
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
result[key] = deepClone(obj[key], map);
}
}
return result;
}
- WeakMap 是理想选择:键必须是对象,且不阻止垃圾回收
- 每次进入递归前先查缓存,命中就直接返回已有拷贝,断掉循环链
进一步支持常见内置类型
实际项目中常需保留 Date、RegExp、Map、Set 的行为。可在类型判断分支中分别处理:
function deepClone(obj, map = new WeakMap()) {
if (obj === null || typeof obj !== 'object') return obj;
if (map.has(obj)) return map.get(obj);
let result;
// 类型分发
if (obj instanceof Date) {
result = new Date(obj.getTime());
} else if (obj instanceof RegExp) {
result = new RegExp(obj);
} else if (obj instanceof Map) {
result = new Map();
obj.forEach((val, key) => {
result.set(deepClone(key, map), deepClone(val, map));
});
} else if (obj instanceof Set) {
result = new Set();
obj.forEach(val => result.add(deepClone(val, map)));
} else {
result = Array.isArray(obj) ? [] : {};
}
map.set(obj, result);
// 只对普通对象/数组遍历属性
if (result && !(result instanceof Date) && !(result instanceof RegExp) &&
!(result instanceof Map) && !(result instanceof Set)) {
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
result[key] = deepClone(obj[key], map);
}
}
}
return result;
}
- 对
Date和RegExp直接构造新实例 -
Map/Set需遍历元素并递归克隆键与值 - 函数(
typeof obj === 'function')、undefined、Symbol键默认不拷贝(也可按需添加)
注意事项与替代建议
手写递归深拷贝虽有助于理解原理,但在生产环境更推荐:
- 使用成熟库如
lodash.cloneDeep(已妥善处理所有边界) - 简单场景可考虑
JSON.parse(JSON.stringify(obj)),但会丢失函数、undefined、Date 对象、循环引用、Symbol 等 - 注意性能:深层嵌套或超大对象可能引发调用栈溢出或卡顿
不复杂但容易忽略的是循环引用检测——这是手写深拷贝从“能跑”到“健壮”的分水岭。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










