深拷贝需递归遍历所有嵌套层级,对基础类型直接返回,对引用类型新建实例并递归复制属性或元素,关键在于精准类型识别(用Object.prototype.toString.call)、避免循环引用(WeakMap缓存)及保持原型链与不可枚举属性。

深拷贝的核心是递归遍历所有嵌套层级,对每个值类型做对应处理:基础类型直接返回,引用类型(对象、数组、Date、RegExp 等)新建实例并递归复制其属性或元素。关键在于正确识别类型、避免循环引用、处理特殊内置对象。
识别类型并分类处理
不能只用 typeof(它对数组、null、日期都返回 "object"),应结合 Object.prototype.toString.call() 精准判断:
-
[object Object]→ 普通对象,遍历 key 递归拷贝 -
[object Array]→ 数组,用map或for递归拷贝每一项 -
[object Date]→ 新建new Date(date.getTime()) -
[object RegExp]→ 新建new RegExp(regexp.source, regexp.flags) -
[object Map]→ 新建 Map,遍历entries()递归拷贝键值 -
[object Set]→ 新建 Set,遍历values()递归拷贝每个值 -
null和基础类型(string/number/boolean/symbol/bigint/undefined)→ 直接返回
防止循环引用导致栈溢出
对象内部可能包含自身引用(如 a.b = a),递归时需记录已拷贝过的源对象及其对应的新对象,再次遇到时直接返回缓存结果:
- 用
WeakMap存储映射关系(键为原始对象,不阻止 GC) - 每次进入递归前先查 WeakMap,存在则直接返回对应拷贝体
- 新建对象后立即存入 WeakMap,再开始属性/元素的递归复制
保持原型链和不可枚举属性
默认 Object.assign 或展开运算符会丢失原型和不可枚举属性。应使用 Object.getPrototypeOf() 和 Object.getOwnPropertyDescriptors() 复制:
立即学习“Java免费学习笔记(深入)”;
- 对普通对象:用
Object.create(Object.getPrototypeOf(obj))创建新对象 - 用
Object.defineProperties(newObj, Object.getOwnPropertyDescriptors(obj))复制所有属性(含 getter/setter、writable/enumerable/configurable) - 对数组,可直接
Array.from(arr)或new Array(arr.length),再逐项赋值(保持 length 和索引属性)
完整手写示例(含循环引用支持)
以下是一个轻量但覆盖主流场景的实现:
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 Date]':
cloned = new Date(obj.getTime());
break;
case '[object RegExp]':
cloned = new RegExp(obj.source, obj.flags);
break;
case '[object Array]':
cloned = new Array(obj.length);
seen.set(obj, cloned);
for (let i = 0; i < obj.length; i++) {
cloned[i] = deepClone(obj[i], seen);
}
break;
case '[object Map]':
cloned = new Map();
seen.set(obj, cloned);
for (const [k, v] of obj.entries()) {
cloned.set(deepClone(k, seen), deepClone(v, seen));
}
break;
case '[object Set]':
cloned = new Set();
seen.set(obj, cloned);
for (const item of obj.values()) {
cloned.add(deepClone(item, seen));
}
break;
default:
cloned = Object.create(Object.getPrototypeOf(obj));
seen.set(obj, cloned);
const descriptors = Object.getOwnPropertyDescriptors(obj);
for (const key in descriptors) {
if (descriptors.hasOwnProperty(key)) {
Object.defineProperty(
cloned,
key,
{
...descriptors[key],
value: deepClone(descriptors[key].value, seen)
}
);
}
}
}
return cloned;
}
这个函数能处理对象、数组、Date、RegExp、Map、Set,保留原型、属性描述符和循环引用。不支持 ArrayBuffer、TypedArray、Promise、Error 等更边缘类型,如需可按相同模式扩展。


















