深拷贝通过递归遍历并重建引用类型实例来避免共享内存,利用WeakMap处理循环引用,结合Object.getPrototypeOf和Object.create保留原型链,精确识别类型并分别构造新实例。

深拷贝的核心是递归遍历对象或数组的每个属性,对引用类型(如对象、数组、日期、正则等)创建新实例并复制内容,避免共享内存地址。原型链原理在这里主要体现在:通过 Object.getPrototypeOf() 获取原对象的原型,并用 Object.create() 为新对象设置相同原型,从而保留继承关系和方法行为。
处理基础类型与循环引用
深拷贝必须跳过 null、undefined、原始值(字符串、数字、布尔、symbol、bigint),它们直接返回即可。关键难点是检测并处理循环引用——否则递归会无限进行。可用 WeakMap 缓存已拷贝过的对象,以原对象为 key,新对象为 value,在每次进入对象前先查表。
- 用
WeakMap存储「源对象 → 拷贝后对象」映射,保证键是对象且不影响垃圾回收 - 遇到已存在映射,直接返回缓存结果,打断循环
- 原始值(包括
function)按需决定是否拷贝:通常函数不深拷(保留引用),也可用eval或toString+new Function复制,但有安全与兼容风险,一般跳过
识别并构造不同内置类型
不能只用 typeof,它对对象、数组、null 都返回 "object"。应结合 Object.prototype.toString.call() 精确判断类型,再分情况构造新实例:
-
普通对象:用
Object.create(Object.getPrototypeOf(obj))创建带相同原型的新空对象 -
数组:用
Array.from(arr)或new Array(arr.length),再逐项赋值 -
Date:用
new Date(obj.getTime()) -
RegExp:用
new RegExp(obj.source, obj.flags) -
Map / Set:分别用
new Map([...map])和new Set([...set]) -
ArrayBuffer / TypedArray:用
obj.slice(0)或new obj.constructor(obj)
递归拷贝自有属性并保持原型链
对普通对象或数组,获取其所有可枚举自有属性(Object.keys() 或 Reflect.ownKeys()),遍历并递归调用深拷贝函数。注意:Reflect.ownKeys() 能拿到 symbol 属性,更完整;而设置新对象属性时,需用 Object.defineProperty() 保留 configurable、enumerable、writable 等描述符(若需完全保真)。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
立即学习“Java免费学习笔记(深入)”;
- 先用
Object.getPrototypeOf(obj)取出原型 - 用
Object.create(proto)创建新对象,确保原型链一致 - 对每个 key,读取
Object.getOwnPropertyDescriptor(obj, key),再用Object.defineProperty(newObj, key, descriptor)设置,兼顾 getter/setter 和不可写属性 - 对值递归调用深拷贝函数,把结果设为新属性值
完整手写示例(含原型链支持)
以下是一个精简但功能完整的实现,支持对象、数组、Date、RegExp、Map、Set、TypedArray,并正确继承原型:
function deepClone(obj, seen = new WeakMap()) {
if (obj === null || typeof obj !== 'object') return obj;
if (seen.has(obj)) return seen.get(obj);
const tag = Object.prototype.toString.call(obj);
let cloned;
switch (tag) {
case '[object Object]':
cloned = Object.create(Object.getPrototypeOf(obj));
break;
case '[object Array]':
cloned = [];
break;
case '[object Date]':
cloned = new Date(obj.getTime());
break;
case '[object RegExp]':
cloned = new RegExp(obj.source, obj.flags);
break;
case '[object Map]':
cloned = new Map(obj);
break;
case '[object Set]':
cloned = new Set(obj);
break;
case '[object ArrayBuffer]':
cloned = obj.slice(0);
break;
default:
if (obj instanceof Uint8Array) {
cloned = new Uint8Array(obj);
} else {
cloned = Object.create(Object.getPrototypeOf(obj));
}
}
seen.set(obj, cloned);
if (tag === '[object Object]' || tag === '[object Array]') {
const keys = Reflect.ownKeys(obj);
for (const key of keys) {
const desc = Object.getOwnPropertyDescriptor(obj, key);
Object.defineProperty(
cloned,
key,
{
...desc,
value: deepClone(desc.value, seen)
}
);
}
}
return cloned;
}
这个函数在创建对象时显式使用 Object.create() 绑定原型,后续属性复制也保留了属性描述符,真正做到了“原型链可继承、结构可还原、引用不共享”。

















