reflect 本身不提供深拷贝能力,也无法直接保留原型链;它仅通过 ownkeys、getownpropertydescriptor 等方法安全获取元信息,深拷贝逻辑需手动递归实现,原型链须显式设置,属性描述符需逐个还原。

Reflect 本身不提供深拷贝能力,也无法直接保留原型链。所谓“利用 Reflect 实现安全的深拷贝并保留属性描述符与原型链”,本质是组合使用 Reflect 的元操作能力(如 ownKeys、getOwnPropertyDescriptor)配合 Object.setPrototypeOf 和 Object.defineProperty,构建一个**可控、可扩展、保元信息**的浅层复制基础——再在此之上递归处理嵌套值。真正的“深”逻辑必须手动实现,且原型链需显式还原。
只靠 Reflect 无法完成深拷贝
Reflect 是一套静态方法集合,用于统一拦截对象基本操作(get/set/defineProperty等),它不负责内存分配、类型判断或递归遍历。例如:
-
Reflect.ownKeys()只返回键,不读值; -
Reflect.getOwnPropertyDescriptor()只读单个描述符,不递归; -
Reflect.setPrototypeOf()可设原型,但不能自动克隆原型对象本身。
因此,任何“Reflect 深拷贝”方案,核心仍是手写递归逻辑,Reflect 仅承担更安全、更完整的元信息获取与设置职责。
macOS 微信消息自动化工具。通过 GUI 自动化实现:发送消息给指定联系人、读取聊天内容、监控新消息。适用于需要自动化微信操作的场景,如定时发送、批量回复、消息备份等。依赖 peekaboo 进行屏幕截图和 UI 交互。仅支持 macOS。开源地址:https://github.com/chairmanmia...
保留完整属性描述符的关键步骤
要让拷贝后的对象在行为上尽可能接近原对象(比如不可枚举属性、getter/setter、Symbol 键、configurable 状态),必须绕过简单赋值,走描述符路径:
- 用
Reflect.ownKeys(source)获取全部自有键(含 Symbol 和不可枚举字符串键); - 对每个
key,调用Object.getOwnPropertyDescriptor(source, key)(注意:不是 Reflect 版本,因后者在某些环境下对 accessor 支持不稳定); - 若描述符存在
get或set,原样传入Object.defineProperty(target, key, desc); - 若为数据属性(
value字段存在),则对value递归执行深拷贝逻辑,再塞回新描述符中; - 跳过
undefined描述符(说明是继承属性,不应复制)。
原型链不能“自动继承”,必须显式设置
新对象默认原型是 Object.prototype。要还原原始原型链,需两步:
- 创建空对象时用
Object.create(Object.getPrototypeOf(source)),而非{}; - 拷贝完成后,再用
Object.setPrototypeOf(target, Object.getPrototypeOf(source))做一次校验性设置(兼容旧环境); - 注意:若原对象原型是 null(如
Object.create(null)),需特殊处理,避免设成Object.prototype。
循环引用与不可配置属性的容错处理
深拷贝中这两类问题极易导致崩溃或静默失败:
- 用
WeakMap缓存已处理过的源对象引用,遇到重复出现的 source 直接返回对应 target,避免无限递归; - 对不可配置(
configurable: false)的属性,若目标对象已有同名属性且不可配置,Object.defineProperty会抛错,此时应提前检查Object.getOwnPropertyDescriptor(target, key)并跳过或降级为只读赋值; - 冻结(
Object.isFrozen)或密封(Object.isSealed)对象,需先判断是否可扩展,否则跳过整对象复制或抛出明确错误。










