深拷贝自定义类实例必须显式处理构造逻辑和私有状态,因其实例含原型、方法、不可枚举属性及Symbol字段;正确做法是:获取原原型→Object.create创建新实例→用Object.getOwnPropertyDescriptors获取所有自有描述符→递归深拷贝value→Object.defineProperties定义→配合WeakMap处理循环引用。

深拷贝自定义类实例不能靠通用递归或 JSON 方法,必须显式处理构造逻辑和私有状态——因为类实例不是普通对象,它有原型、方法、不可枚举属性,甚至可能含闭包或 Symbol 私有字段。
识别并保留构造器与原型链
直接用 Object.assign 或朴素递归会丢掉原型和方法。正确做法是:先用 Object.getPrototypeOf(obj) 获取原实例原型,再用 Object.create(proto) 创建新对象,确保继承关系 intact。
- 避免用
new obj.constructor()—— 构造函数可能依赖参数、副作用或 this 绑定,盲目调用易出错 - 优先走「原型继承 + 属性赋值」路径:创建空实例 → 复制自有可枚举/不可枚举属性(包括 Symbol 键)→ 不触发 constructor
- 若类明确支持克隆(如提供
clone()方法),应优先调用该方法而非自行重建
手动复制自有属性(含 Symbol 和不可枚举项)
类实例的字段可能藏在 Symbol 键、Object.getOwnPropertyNames() 或 Object.getOwnPropertySymbols() 中,仅靠 for...in 会漏掉。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 用
Object.getOwnPropertyDescriptors(obj)获取所有自有属性描述符(含 get/set、writable、enumerable、configurable) - 对每个 descriptor 递归深拷贝 value(注意:getter/setter 函数不拷贝,只保留原引用或跳过)
- 用
Object.defineProperties(newObj, descriptors)批量定义,保持属性特性(如只读、不可配置)
特殊字段需按类约定单独处理
很多类内部维护非公开状态(如缓存、事件监听器、私有字段 #field),这些无法通过反射访问,必须由类自身暴露接口或开发者约定规则。
立即学习“Java免费学习笔记(深入)”;
- ES2022 私有字段(
#name)完全不可反射,只能靠类提供toJSON()、serialize()或clone()方法导出可拷贝数据 - 若类有静态
from()或deserialize()方法,可用其配合序列化数据重建实例 - 第三方库如 Lodash 的
cloneDeepWith允许传入 customizer 函数,在遇到特定构造器时返回定制克隆结果
循环引用与缓存机制不能省
类实例之间常存在引用闭环(如父子关系、观察者列表),不加缓存会导致栈溢出或无限递归。
- 始终用
WeakMap缓存源对象 → 克隆对象映射,首次克隆时新建,重复出现时直接返回已有结果 - 缓存应在进入克隆前检查,而不是等属性遍历完才判断——否则已递归进去了
- 注意 WeakMap 键必须是对象,基本类型或 null/undefined 不参与缓存逻辑

















