深拷贝需区分普通对象与特殊对象:普通对象和数组递归复制;date、regexp、map、set等须用构造函数重建;symbol、function、undefined需特殊处理;循环引用用weakmap避免死循环。

JavaScript 中对象 API 在深拷贝实现中,对普通对象和特殊对象(如 Date、RegExp、Map、Set、ArrayBuffer、TypedArray、Error、Function、Symbol、undefined 等)的属性复制,不能一概而论——必须区分类型、检测结构、按需处理。核心在于:**普通对象可递归遍历复制;特殊对象需单独识别并构造新实例,否则会丢失行为或报错。**
普通对象与数组的递归复制
普通对象(plain object)和数组是深拷贝的基础目标,可通过 typeof obj === 'object' 且非 null 初步识别,再用 Array.isArray() 或 Object.prototype.toString.call() 精确判断。
- 数组:新建空数组
[],遍历原数组每一项,递归调用深拷贝函数赋值 - 普通对象:新建空对象
{},用Object.keys()或for...in + hasOwnProperty遍历自有可枚举属性,逐个深拷贝后赋值 - 注意跳过原型链属性、不可枚举属性(如
__proto__)、getter/setter 属性(除非显式要求保留访问器逻辑)
Date、RegExp 等内置对象的构造式复制
这些对象不是普通键值对结构,直接遍历属性会漏掉内部状态(如 Date 的毫秒时间戳、RegExp 的 flags 和 source)。必须用其构造函数重建:
-
Date:用new Date(obj.getTime())或new Date(+obj) -
RegExp:用new RegExp(obj.source, obj.flags)(注意兼容gimyus标志) -
Error:新建new Error(obj.message),但堆栈信息(stack)通常不可复制,属只读属性 -
Map / Set:分别用new Map([...obj])和new Set([...obj]),确保内部元素也深拷贝
Symbol、函数、undefined 与循环引用的特殊处理
这些值在标准 JSON 方法中会被静默丢弃或报错,手写深拷贝必须主动决策:
-
Symbol:无法被 JSON 序列化,也不能用字面量重建(每个 Symbol 唯一),通常选择跳过或浅层保留(clone[key] = key) -
Function:本质是不可序列化的代码逻辑,多数深拷贝方案直接返回原函数(即“浅拷贝函数”),若需隔离可包装为字符串再eval(不推荐)或明确禁止 -
undefined:JSON 方法会忽略该属性,手写时应显式保留(clone[key] = obj[key]),因它是合法属性值 - 循环引用:用
WeakMap缓存已拷贝对象,每次进入对象前先查缓存,避免无限递归
属性描述符与原型链的取舍
标准深拷贝(包括 structuredClone 和 Lodash)默认不复制属性描述符(writable、enumerable、configurable)和原型链:
- 若需保留原型,可用
Object.setPrototypeOf(clone, Object.getPrototypeOf(obj)) - 若需复制描述符,需配合
Object.getOwnPropertyDescriptors()和Object.defineProperties(),但会显著增加复杂度和性能开销 - 实际业务中,95% 场景只需数据内容隔离,无需还原元信息
大量免费API接口:立即使用
涵盖生活服务API、金融科技API、企业工商API、等相关的API接口服务。免费API接口可安全、合规地连接上下游,为数据API应用能力赋能!











