Skip to content

Latest commit

 

History

History
186 lines (142 loc) · 5.36 KB

File metadata and controls

186 lines (142 loc) · 5.36 KB

7. Object.getOwnPropertyDescriptors()

本章将介绍由 Jordan Harband 和 Andrea Giammarchi 提供的ECMAScript提案——「Object.getOwnPropertyDescriptors()」

7.1 概述

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 } }

7.2 Object.getOwnPropertyDescriptors()

Object.getOwnPropertyDescriptors(obj)接受一个对象obj,然后返回一个对象:

遍历obj的属性(非继承的),然后在结果集中返回其相同的key和属性描述符对应的value。 属性描述符就是对属性特性的说明(其值,是否可写,等)。有关更多信息,请参阅“Speaking JavaScript” 相关章节 “Property Attributes and Property Descriptors”

这是使用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;
}

7.3 使用Object.getOwnPropertyDescriptors()的实例

7.3.1 用例: 复制属性到一个对象中

自ES6以来,JavaScript已有一个复制属性的工具方法:Object.assign()。 但是,此方法使用简单的get和set操作来复制键为所求键的属性:

const value = source[key]; // get
target[key] = value; // set

这意味着它不能正确地复制带有非默认属性的属性(getters, setters, 不可写描述符, 等)。 下面的例子举例说明了此限制。这个对象source有一个键为foo的setter:

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到一个目标对象就会失败:

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 }

7.3.2 用例: 复制对象

浅拷贝跟复制属性有点类似,这也是为什么Object.getOwnPropertyDescriptors()同样适用于这个用例。

这次,我们用Object.create(),它有两个参数:

第一个参数用来制定需要返回的对象属性。

可选的第二个参数是一个属性描述符集合,类似于Object.getOwnPropertyDescriptors()返回的集合。

const clone = Object.create(Object.getPrototypeOf(obj),
    Object.getOwnPropertyDescriptors(obj));

7.3.3 用例:跨平台对象常量与任意原型

如果你要给对象常量创建带任意原型的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,
    }
);

7.4 缺陷: 复制使用super的方法

使用super的方法与其父对象(存储在其中的对象)紧密地连接着。 目前没有办法将这样的方法复制或移动到不同的对象。


首页:探索ES2016和ES2017

上一章:新的字符串方法:padStart和padEnd

下一章: 在函数参数列表和调用时后缀逗号