object.assign仅拷贝可枚举自有属性的值,不复制属性描述符(configurable/enumerable/writable)、getter/setter、原型链及proxy等流式行为,导致响应式失效、元信息丢失。

Object.assign 本身不处理属性描述符(如 configurable、enumerable、writable)和继承链上的属性,它只做“可枚举自有属性”的逐个赋值。当你用它拷贝一个带继承描述符或流式结构(比如 Proxy、带 getter/setter 的对象)的对象时,隐患不是“拷得不够深”,而是“根本没拷对”——它会丢掉元信息,把原本受控的访问逻辑变成普通字段。
Object.assign 不复制属性描述符
它只读取属性值并写入目标对象,不调用 Object.defineProperty,因此:
- getter/setter 会被执行后取返回值,然后作为普通数据写入(失去响应性)
-
configurable: false或writable: false的属性,在新对象里默认变成true - 不可枚举属性(
enumerable: false)直接被忽略,不会出现在拷贝结果中 - 原型链上的属性一律不拷贝,哪怕它们是可枚举的
流式对象(如 Proxy、Observable)会失效
像 Vue 响应式对象、MobX observable、或自定义 Proxy 实例,其行为依赖于拦截机制(get/set trap)。Object.assign 只触发一次 get 获取当前值,然后把结果当作静态值赋给新对象:
- 原 Proxy 的响应式更新、副作用、依赖追踪全部丢失
- 拷贝后的对象是纯普通对象,再修改它不会触发任何监听或派生计算
- 如果原对象有懒计算 getter(如
get fullName() { return this.first + ' ' + this.last }),拷贝后只剩一个固定字符串
替代方案:按需选择更精准的复制方式
不要强行用 Object.assign 处理这类对象。根据目标明确选型:
- 需要保留描述符?用
Object.getOwnPropertyDescriptors()+Object.defineProperties()手动重建 - 要浅拷贝且兼容原型?用
Object.create(Object.getPrototypeOf(obj), Object.getOwnPropertyDescriptors(obj)) - 处理 Proxy 或响应式对象?优先用其官方克隆方法(如 Vue 的
toRaw()+reactive(),或 MobX 的clone()) - 只是想解构再重组?用展开运算符
{...obj}行为与 Object.assign 一致,同样不保描述符,慎用于流式场景
本质上,Object.assign 是“值搬运工”,不是“结构复制器”。遇到描述符或流式行为,就得换工具——否则看似复制成功,实则已切断关键契约。










