Object.getOwnPropertyDescriptors 配合 Object.defineProperties 可实现保留属性特性的浅拷贝,而普通赋值或展开运算符会丢失不可枚举属性、访问器及 descriptor 元信息。

Object.getOwnPropertyDescriptors 本身不执行拷贝,它只是**读取**对象自身所有属性的完整描述符(包括 value、writable、enumerable、configurable、get、set),但配合 Object.defineProperties 就能实现「保留属性特性的浅拷贝」——即不仅复制值,还精确复刻每个属性的可枚举性、可写性、可配置性及访问器行为。
为什么不能用普通赋值或展开运算符?
普通方式(如 {...obj} 或 Object.assign({}, obj))只复制 可枚举且自有 的数据属性的 value,会丢失:
- 不可枚举属性(
enumerable: false) - 访问器属性(
get/set) -
writable、configurable等元信息
完整浅拷贝属性描述符的正确写法
分两步:先读取所有自有属性描述符,再批量定义到新对象上:
function shallowCopyWithDescriptors(obj) {
if (obj == null || typeof obj !== 'object') return obj;
const descriptors = Object.getOwnPropertyDescriptors(obj);
return Object.defineProperties({}, descriptors);
}
<p>// 示例
const source = {
a: 1,
get b() { return this.a * 2; }
};
Object.defineProperty(source, 'c', {
value: 'hidden',
enumerable: false,
writable: false,
configurable: true
});</p><p>const copy = shallowCopyWithDescriptors(source);
console.log(copy.a); // 1
console.log(copy.b); // 2(访问器正常工作)
console.log('c' in copy); // true(不可枚举属性仍存在)
console.log(Object.getOwnPropertyDescriptor(copy, 'c').writable); // false(特性保留)
注意:这只是「浅拷贝描述符」,不是深拷贝
该方法只处理目标对象自身的属性,不递归处理嵌套对象。例如:
- 如果某个属性值是对象,拷贝后新旧对象共享该引用
- 访问器中的
this指向新对象,行为保持一致(因get/set函数被原样复制) - Symbol 属性也会被包含在
getOwnPropertyDescriptors结果中,自动支持
兼容性与替代方案
Object.getOwnPropertyDescriptors 是 ES2017 特性,现代浏览器和 Node.js ≥ 8.10 均支持。若需兼容旧环境:
- 可用
Object.getOwnPropertyNames+Object.getOwnPropertySymbols手动遍历 +Object.getOwnPropertyDescriptor - 但无法一次性获取所有描述符,代码更冗长,且需分别处理数据属性和访问器属性逻辑


















