浅拷贝不保留属性描述符,所有属性均变为默认描述符(writable/enumerable/configurable 为 true),访问器退化为数据属性;需用 Object.defineProperties 或 Object.create 配合 Object.getOwnPropertyDescriptors 才能完整复刻。

浅拷贝不会传递属性描述符,它只复制属性的当前值,不保留 writable、enumerable、configurable 或访问器(get/set)等元信息。
浅拷贝本质是“值复制”,不是“描述符继承”
无论用展开运算符 {...obj}、Object.assign() 还是手动遍历赋值,结果都一样:新对象的属性全部变成默认描述符的数据属性——即 writable: true、enumerable: true、configurable: true,哪怕原属性是只读、不可枚举或由 getter 控制。
- 原对象中
Object.defineProperty(obj, 'x', { value: 1, writable: false })→ 浅拷贝后copy.x = 2不会报错(因为 copy.x 已是可写的) - 原对象含
get name() { return this._name; }→ 浅拷贝后copy.name变成普通数据属性,不再触发 getter - 原属性设为
enumerable: false→ 浅拷贝后该属性在Object.keys()和for...in中都会出现
哪些操作会丢失描述符
以下常见方式均不保留原始描述符:
-
const copy = { ...obj }:忽略 Symbol 键、不可枚举属性,且所有属性变为默认描述符 -
Object.assign({}, obj):仅复制可枚举的自有属性,访问器退化为数据属性,configurable和writable状态丢失 -
for...in+ 手动赋值:copy[key] = obj[key]—— 完全绕过描述符机制,等价于直接设置数据属性
想保留描述符?必须显式操作
若需完整复刻属性行为(比如克隆带 setter 的配置对象),不能依赖浅拷贝,而要用底层 API:
立即学习“Java免费学习笔记(深入)”;
-
Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)):逐个重建描述符,包括访问器、不可写、不可枚举等 -
Object.create(Object.getPrototypeOf(source), Object.getOwnPropertyDescriptors(source)):连原型和所有自有属性描述符一并复制 - 注意:
Object.getOwnPropertyDescriptors()不包含原型链上的属性,只处理对象自身
实际影响常被忽略
在封装类、响应式系统或配置校验逻辑中,描述符丢失可能导致意外行为:
- 只读字段被意外修改(因浅拷贝后变可写)
- 依赖
propertyIsEnumerable的序列化逻辑出错(因不可枚举属性变可枚举) - 访问器逻辑失效(如 computed 属性不再响应变化)
- 冻结对象(
Object.freeze())浅拷贝后,新对象完全可变


















