浅拷贝丢失属性描述符是因为其本质是“读取—赋值”过程,不复制元信息;object.assign、展开运算符等仅获取getter返回值并写入普通属性,导致accessor、writable、enumerable、configurable等描述符全部失效。

浅拷贝不会传递属性描述符(如 get、set、writable、enumerable、configurable),它只读取并复制属性的当前值,丢失所有元信息。
为什么描述符在浅拷贝中丢失
Object.assign()、展开运算符({...obj})、for...in 循环等浅拷贝方式,本质是“读取—赋值”过程:它们调用属性的 getter(如果存在)拿到返回值,再以普通数据属性形式写入目标对象。原始的访问器定义、只读标记、不可枚举状态等描述符信息完全不参与该流程。
- getter/setter 被执行一次后变成静态值,新对象里只剩一个普通
value属性 -
writable: false的只读属性,在拷贝后默认变为可写(因赋值操作隐式设为writable: true) -
enumerable: false或configurable: false的属性会被忽略(如通过Object.defineProperty定义的不可枚举属性)
哪些属性会受影响
以下几类属性在浅拷贝中必然失效或行为异常:
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
- 带
get/set的访问器属性(如obj.count是 getter,拷贝后变成固定数字) - Symbol 键名属性(
Object.assign和展开运算符不遍历 Symbol) - 不可枚举属性(
enumerable: false,例如Object.prototype.toString) - 原型链上的继承属性(浅拷贝只处理自有属性,不复制原型)
如何保留描述符完成真正拷贝
要完整复刻属性及其描述符,必须绕过“读取—赋值”路径,直接操作描述符本身:
- 用
Object.getOwnPropertyDescriptors(obj)获取所有自有属性的完整描述符对象(含 Symbol 和不可枚举属性) - 用
Object.defineProperties(target, descriptors)将描述符批量重定义到新对象 - 若需保留原型链,先用
Object.create(Object.getPrototypeOf(obj))创建继承关系,再定义属性
实际效果对比示例
假设源对象有 getter 和私有状态:
const source = {
_x: 10,
get x() { return this._x * 2; },
set x(val) { this._x = Math.max(0, val); }
};
-
const bad = {...source}→bad.x是数字20,无法再赋值 -
const good = Object.defineProperties({}, Object.getOwnPropertyDescriptors(source))→good.x仍具响应式读写能力
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










