手写递归深拷贝函数需先判断null和原始类型直接返回,再用weakmap处理循环引用,区分date、regexp、map、set等内置类型并递归克隆,保留原型链,过滤原型属性,补充symbol键支持。

手写递归实现的深拷贝函数,核心是判断数据类型、处理循环引用、递归遍历对象/数组属性,并正确复制每层结构。
基础版本:处理对象和数组
最简递归深拷贝需区分原始类型与引用类型。原始类型(string、number、boolean、null、undefined、symbol、bigint)直接返回;引用类型(Object、Array)递归处理:
function deepClone(obj) {
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 等特殊对象,且无法处理循环引用,遇到会栈溢出。
增强版本:支持常见内置类型
扩展对 Date、RegExp、Map、Set 的识别和克隆:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
function deepClone(obj, seen = new WeakMap()) {
if (obj === null || typeof obj !== 'object') return obj;
// 处理循环引用
if (seen.has(obj)) return seen.get(obj);
let result;
const Ctor = obj.constructor;
if (obj instanceof Date) {
result = new Date(obj);
} 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, seen), deepClone(val, seen));
});
} else if (obj instanceof Set) {
result = new Set();
obj.forEach(val => result.add(deepClone(val, seen)));
} else if (Array.isArray(obj)) {
result = [];
} else {
result = Object.create(Object.getPrototypeOf(obj));
}
seen.set(obj, result);
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
result[key] = deepClone(obj[key], seen);
}
}
return result;
}
- WeakMap 存储原对象 → 克隆对象映射,避免无限递归
- 用 Object.create(Object.getPrototypeOf(obj)) 保留原型链(比
{}更准确) - 对 Map/Set 使用
forEach遍历,分别克隆键与值
关键细节说明
手写深拷贝必须注意几个易错点:
-
typeof null === 'object' → 必须先单独判断
obj === null -
for...in 会遍历原型属性 → 加
hasOwnProperty过滤 -
函数、undefined、symbol 在对象中可被枚举,但通常不深拷贝函数(直接赋值即可),symbol 键需用
Object.getOwnPropertySymbols()补充处理 -
不可枚举属性(如
Object.defineProperty设置的)需要额外用getOwnPropertyDescriptors处理(进阶需求)
简单补充 symbol 键支持
若需拷贝 symbol 类型的 key,可在循环后添加:
const symbols = Object.getOwnPropertySymbols(obj);
for (let sym of symbols) {
result[sym] = deepClone(obj[sym], seen);
}
这样就能覆盖所有可枚举 + symbol 属性,同时保持类型语义和原型继承关系。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










