Object.getOwnPropertyDescriptors()
Object.getOwnPropertyDescriptors()
是 ECMAScript 8(ES2017)引入的一个静态方法,用于获取对象所有自身属性的描述符。与 Object.getOwnPropertyDescriptor()
不同,它一次性返回对象的所有属性描述符,包括可枚举和不可枚举属性。这一特性在对象复制、属性代理等场景中非常实用。
基本语法与返回值
方法签名如下:
Object.getOwnPropertyDescriptors(obj)
- 参数:
obj
是目标对象。 - 返回值:一个包含所有自身属性描述符的对象,键为属性名,值为属性描述符对象(即
{value, writable, enumerable, configurable}
或{get, set, enumerable, configurable}
)。
示例:获取普通对象的属性描述符
const obj = {
name: 'Alice',
age: 30,
get greeting() {
return `Hello, ${this.name}!`;
}
};
const descriptors = Object.getOwnPropertyDescriptors(obj);
console.log(descriptors);
// 输出:
// {
// name: { value: 'Alice', writable: true, enumerable: true, configurable: true },
// age: { value: 30, writable: true, enumerable: true, configurable: true },
// greeting: { get: [Function: greeting], set: undefined, enumerable: true, configurable: true }
// }
与 Object.getOwnPropertyDescriptor()
的区别
Object.getOwnPropertyDescriptor()
只能获取单个属性的描述符,而 Object.getOwnPropertyDescriptors()
一次性返回所有属性的描述符。例如:
const singleDescriptor = Object.getOwnPropertyDescriptor(obj, 'name');
console.log(singleDescriptor); // { value: 'Alice', writable: true, enumerable: true, configurable: true }
实际应用场景
1. 深度复制对象属性
传统的 Object.assign()
只能复制可枚举属性和值,无法复制属性的描述符(如 getter
/setter
)。结合 Object.defineProperties()
可以实现完整复制:
const source = {
_id: 1,
get id() {
return this._id;
}
};
const shallowCopy = Object.assign({}, source);
console.log(Object.getOwnPropertyDescriptor(shallowCopy, 'id')); // { value: 1, ... } (getter 丢失)
// 使用描述符复制
const deepCopy = Object.create(
Object.getPrototypeOf(source),
Object.getOwnPropertyDescriptors(source)
);
console.log(Object.getOwnPropertyDescriptor(deepCopy, 'id')); // { get: [Function: id], ... } (保留 getter)
2. 创建不可变对象
通过描述符可以精确控制对象的可写性:
const immutable = Object.defineProperties(
{},
Object.getOwnPropertyDescriptors({
key: 'value',
get readOnly() {
return 'constant';
}
})
);
Object.freeze(immutable); // 进一步冻结对象
3. 混入(Mixin)模式
在组合多个对象的属性时,保留完整的属性特性:
const mixin = (target, ...sources) => {
sources.forEach(source => {
Object.defineProperties(
target,
Object.getOwnPropertyDescriptors(source)
);
});
return target;
};
const objA = { get data() { return 42; } };
const objB = { log() { console.log(this.data); } };
const mixed = mixin({}, objA, objB);
mixed.log(); // 42
处理 Symbol 属性
该方法同样支持 Symbol 类型的属性键:
const symbolKey = Symbol('private');
const obj = {
[symbolKey]: 'secret',
public: 'info'
};
console.log(Object.getOwnPropertyDescriptors(obj));
// 输出:
// {
// public: { value: 'info', writable: true, enumerable: true, configurable: true },
// [Symbol(private)]: { value: 'secret', writable: true, enumerable: true, configurable: true }
// }
与 Proxy 结合使用
在代理对象中,可以通过描述符实现高级属性控制:
const handler = {
getOwnPropertyDescriptor(target, prop) {
const desc = Object.getOwnPropertyDescriptor(target, prop);
if (prop.startsWith('_')) {
return { ...desc, enumerable: false }; // 隐藏以下划线开头的属性
}
return desc;
}
};
const target = { _hidden: 'value', visible: 'text' };
const proxy = new Proxy(target, handler);
console.log(Object.getOwnPropertyDescriptors(proxy));
// 输出中 _hidden 的 enumerable 被改为 false
浏览器兼容性与 Polyfill
现代主流浏览器均支持该方法,但对于旧环境可以通过以下 Polyfill 实现:
if (!Object.getOwnPropertyDescriptors) {
Object.getOwnPropertyDescriptors = function(obj) {
const result = {};
for (const key of Reflect.ownKeys(obj)) {
result[key] = Object.getOwnPropertyDescriptor(obj, key);
}
return result;
};
}
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn