

本文为 《JavaScript 新书:探索 ES2016 与 ES2017》的内容章节,你可以点击链接查看完整目录。
本章介绍了 ECMAScript 2017 的 Object.getOwnPropertyDescriptors() 特性 。
概述
Object.getOwnPropertyDescriptors(obj)
返回指定对象 obj
上自有属性对应的属性描述符:
const obj = { [Symbol('foo')]: 123, get bar() { return 'abc' }, }; console.log(Object.getOwnPropertyDescriptors(obj)); // Output: // { [Symbol('foo')]: // { value: 123, // writable: true, // enumerable: true, // configurable: true }, // bar: // { get: [Function: bar], // set: undefined, // enumerable: true, // configurable: true } }
Object.getOwnPropertyDescriptors()
Object.getOwnPropertyDescriptors(obj) 接受一个 obj
对象 并返回一个 result
结果对象:
- 对于
obj
的每个 自有(非继承的)属性,它会添加一个属性,其结果的键是相同的,其值是obj
属性的描述符。
属性描述符描述属性的一些 特征(attributes)(其值,是否可写等)。有关更多信息,请参阅 Sect 。“Speaking JavaScript” 中的 “属性 特征(attributes) 和 属性描述符”。
这是使用 Object.getOwnPropertyDescriptors() 的一个例子:
const obj = { [Symbol('foo')]: 123, get bar() { return 'abc' }, }; console.log(Object.getOwnPropertyDescriptors(obj)); // Output: // { [Symbol('foo')]: // { value: 123, // writable: true, // enumerable: true, // configurable: true }, // bar: // { get: [Function: bar], // set: undefined, // enumerable: true, // configurable: true } }
这是 Object.getOwnPropertyDescriptors() 的实现:
function getOwnPropertyDescriptors(obj) { const result = {}; for (let key of Reflect.ownKeys(obj)) { result[key] = Object.getOwnPropertyDescriptor(obj, key); } return result; }
Object.getOwnPropertyDescriptors() 的用例
用例:拷贝属性到一个对象中
自 ES6 起,JavaScript 已经有复制属性的工具方法了:Object.assign()
。但是,该方法使用了简单的 get
和 set
操作来复制其键为 key
的属性:
const value = source[key]; // get target[key] = value; // set
这意味着它不能正确地复制具有非默认特征(attributes)的属性(getter,setter,不可写属性,等)。以下示例说明了此限制。对象 source
有一个 setter ,其键是 foo
:
const source = { set foo(value) { console.log(value); } }; console.log(Object.getOwnPropertyDescriptor(source, 'foo')); // { get: undefined, // set: [Function: foo], // enumerable: true, // configurable: true }
使用 Object.assign()
将属性 foo
复制到对象 target
则失败了:
const target1 = {}; Object.assign(target1, source); console.log(Object.getOwnPropertyDescriptor(target1, 'foo')); // { value: undefined, // writable: true, // enumerable: true, // configurable: true }
幸运的是,使用 Object.getOwnPropertyDescriptors()
和 Object.defineProperties()
可以一起工作:
const target2 = {}; Object.defineProperties(target2, Object.getOwnPropertyDescriptors(source)); console.log(Object.getOwnPropertyDescriptor(target2, 'foo')); // { get: undefined, // set: [Function: foo], // enumerable: true, // configurable: true }
用例:克隆对象
浅拷贝(浅克隆)类似于复制属性,这里 Object.getOwnPropertyDescriptors()
也是一个很好的选择。
这次,我们使用 Object.create()
,它有两个参数:
- 第一个参数指定它返回对象的原型。
- 可选的第二个参数是类似于
Object.getOwnPropertyDescriptors()
返回的属性描述符集合。
const clone = Object.create(Object.getPrototypeOf(obj), Object.getOwnPropertyDescriptors(obj));
用例:带有任意原型的跨平台对象字面量
要使用对象字面量创建带有任意原型 prot
的对象,语法最好的方法是使用特殊属性 __proto__
:
const obj = { __proto__: prot, foo: 123, };
遗憾的是,这个特性只能保证在浏览器里运行。 常见的解决方法是 Object.create()
和赋值:
const obj = Object.create(prot); obj.foo = 123;
但是现在你也可以使用 Object.getOwnPropertyDescriptors()
:
const obj = Object.create( prot, Object.getOwnPropertyDescriptors({ foo: 123, }) );
另一种方法是使用 Object.assign()
:
const obj = Object.assign( Object.create(prot), { foo: 123, } );
陷阱:拷贝使用 super
的方法
使用 super
的方法与其 home 对象(存储该方法的对象)是强关联的。目前没有办法将这种方法复制或移动到不同的对象中。
原文链接:http://exploringjs.com/es2016-es2017/ch_object-getownpropertydescriptors.html
最新评论
写的挺好的
有没有兴趣翻译 impatient js? https://exploringjs.com/impatient-js/index.html
Flexbox playground is so great!
感谢总结。
awesome!
这个好像很早就看到类似的文章了
比其他的教程好太多了
柯理化讲的好模糊…没懂