object.assign 不能精确复制属性描述符,因其仅复制可枚举自有属性的值,忽略不可枚举属性、getter/setter、继承属性及描述符元信息;需用 object.getownpropertydescriptors 配合 object.defineproperties 实现精确浅拷贝。

Object.assign 本身不会复制属性描述符(如 enumerable、writable、configurable、get/set),它只复制属性的可枚举自有值。也就是说,用 Object.assign({}, obj) 得到的新对象,所有属性都是默认可枚举、可写、可配置的普通数据属性,原始对象中通过 Object.defineProperty 设置的特殊描述符会丢失。
为什么 Object.assign 不能精确复制属性描述符
因为它的设计目标是“合并属性值”,不是“克隆属性元信息”。它遍历的是对象的可枚举自有属性(即 for...in 能访问到、且 hasOwnProperty 为 true 的那些),跳过不可枚举属性、继承属性、getter/setter 属性(除非它们有可枚举的返回值)。
- 不可枚举属性(
enumerable: false)会被忽略 - setter/getter 属性不会被复制,只会复制其当前读取的值(如果有的话)
- 非自有属性(来自原型链)不会被复制
- Symbol 键属性会被复制,但前提是它们可枚举
想精确复制属性描述符,得用 Object.getOwnPropertyDescriptors
这是现代 JavaScript(ES2017+)提供的标准方法,能完整获取一个对象所有自有属性(包括不可枚举、Symbol 键、getter/setter)的描述符,并配合 Object.defineProperties 实现精确浅拷贝:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
-
Object.getOwnPropertyDescriptors(obj)返回一个键为属性名、值为对应 descriptor 对象的字面量 -
Object.defineProperties(target, descriptors)将这些描述符批量定义到目标对象上
示例:
const original = {};
Object.defineProperty(original, 'hidden', {
value: 42,
enumerable: false,
writable: false,
configurable: false
});
Object.defineProperty(original, 'computed', {
get() { return this.hidden * 2; },
enumerable: true
});
<p>const copy = {};
Object.defineProperties(copy, Object.getOwnPropertyDescriptors(original));
// copy.hidden 不可枚举、不可写、不可配置;copy.computed 是 getter —— 完全一致
</p>
注意:这仍是浅拷贝,不解决嵌套引用问题
即使用了 Object.getOwnPropertyDescriptors,它也只是把顶层属性的描述符原样搬过去,对属性值本身的类型不做任何处理:
- 如果某个属性值是对象或数组,复制的仍是该引用,不是新对象
- 不会递归处理嵌套对象的描述符
- 仍属于浅拷贝范畴,只是“更精确”的浅拷贝
常见误区与补充说明
有些开发者误以为 Object.create(obj) 或 Object.assign 能保留描述符,其实都不能:
-
Object.create(obj)创建的是以obj为原型的新对象,不是拷贝属性,更不复制描述符 -
Object.assign(null, obj)会报错(target 必须是对象),Object.assign(123, obj)会自动包装成对象,但结果不可靠且不推荐 - 扩展运算符
{...obj}行为等同于Object.assign({}, obj),同样忽略不可枚举和 getter/setter
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










