object.assign() 无法实现真正严谨的原始对象克隆,仅支持浅拷贝且忽略不可枚举属性、原型链、symbol键、getter/setter及date/regexp等特殊对象;需结合reflect.ownkeys、object.getownpropertydescriptor、object.defineproperty和object.create等手动构建定制化克隆策略。

直接用 Object.assign() 无法实现真正严谨的原始对象克隆,它只做浅拷贝,且会忽略不可枚举属性、原型链、Symbol 键(除非显式列出)、getter/setter 和特殊对象(如 Date、RegExp)。配合 Reflect API 可提升元信息获取能力,但 Reflect 本身不提供深拷贝或属性控制逻辑,需组合其他机制才能逼近“严谨克隆”。关键在于:明确克隆目标(是否保留原型?是否处理 Symbol?是否跳过 accessor?),再用 Reflect 辅助探测,Object.assign 或更底层操作执行赋值。
识别并复制所有自有属性(含不可枚举和 Symbol)
Object.assign() 默认只复制可枚举的自有字符串键属性。要覆盖更全的属性集,需先用 Reflect.ownKeys() 获取全部自有键(包括 Symbol 和不可枚举字符串键),再逐个判断并复制:
- 用
Reflect.ownKeys(obj)得到完整键数组 - 对每个键
key,用Object.getOwnPropertyDescriptor(obj, key)获取属性描述符,判断是否为数据属性(value存在且非 accessor) - 若需保留属性特性(如
writable、configurable),不能用Object.assign()赋值,而应改用Object.defineProperty()
谨慎处理 accessor 属性(getter/setter)
Object.assign() 对 accessor 属性只会调用 getter 并把返回值作为普通数据属性写入目标,丢失原有访问器逻辑。若需保留 accessor,必须显式检测:
- 通过
Object.getOwnPropertyDescriptor()检查get或set是否存在 - 若存在,用
Object.defineProperty(target, key, descriptor)复制整个描述符,而非仅取value - 注意:直接复制 accessor 可能引发副作用(如 getter 中有 this 绑定或副作用逻辑),需评估业务场景是否允许
决定是否保留原型链
Object.assign() 总是将属性复制到新对象({})上,该对象默认继承自 Object.prototype,原始原型丢失。若需继承原对象原型,应使用 Object.create(Object.getPrototypeOf(obj)) 创建目标:
- 目标对象创建:
const clone = Object.create(Object.getPrototypeOf(obj)) - 后续属性复制(含 Symbol、accessor 等)均作用于该
clone上 - 注意:若原对象原型链中有不可扩展/冻结对象,
Object.defineProperty可能抛错,需提前检查Object.isExtensible()
避开常见陷阱:Date、RegExp、Map、Set 等内置对象
Object.assign() 和 Reflect 都无法自动识别并克隆特殊内置对象。例如:
-
new Date()克隆后变成空对象{},因Date实例的[[PrimitiveValue]]不暴露为自有属性 -
new Map()的键值对完全不可见于ownKeys或getOwnPropertyDescriptor - 解决方案:在克隆前做类型检测(
obj instanceof Date、obj.constructor === Map等),对已知类型手动构造新实例并还原内容
不复杂但容易忽略。真正严谨的克隆不是靠单个 API,而是根据需求定制策略:用 Reflect.ownKeys 和 getOwnPropertyDescriptor 全面探查,用 Object.defineProperty 精确控制属性定义,用 Object.create 保持原型,再对特殊内置类型单独兜底。此时 Object.assign() 仅适合最简场景,不宜作为“严谨克隆”的主力工具。
大量免费API接口:立即使用
涵盖生活服务API、金融科技API、企业工商API、等相关的API接口服务。免费API接口可安全、合规地连接上下游,为数据API应用能力赋能!










