Object.getOwnPropertyDescriptors()

前面说过,Object.getOwnPropertyDescriptor方法会返回某个对象属性的描述对象(descriptor)。ES2017 引入了Object.getOwnPropertyDescriptors方法,返回指定对象所有自身属性(非继承属性)的描述对象。

const obj = {
foo: 123,
get bar() { return 'abc' }
}; Object.getOwnPropertyDescriptors(obj)
// { foo:
// { value: 123,
// writable: true,
// enumerable: true,
// configurable: true },
// bar:
// { get: [Function: get 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.assign()无法正确拷贝get属性和set属性的问题。

const source = {
set foo(value) {
console.log(value);
}
}; const target1 = {};
Object.assign(target1, source); Object.getOwnPropertyDescriptor(target1, 'foo')
// { value: undefined,
// writable: true,
// enumerable: true,
// configurable: true }

上面代码中,source对象的foo属性的值是一个赋值函数,Object.assign方法将这个属性拷贝给target1对象,结果该属性的值变成了undefined。这是因为Object.assign方法总是拷贝一个属性的值,而不会拷贝它背后的赋值方法或取值方法。

这时,Object.getOwnPropertyDescriptors方法配合Object.defineProperties方法,就可以实现正确拷贝。

const source = {
set foo(value) {
console.log(value);
}
}; const target2 = {};
Object.defineProperties(target2, Object.getOwnPropertyDescriptors(source));
Object.getOwnPropertyDescriptor(target2, 'foo')
// { get: undefined,
// set: [Function: set foo],
// enumerable: true,
// configurable: true }

上面代码中,两个对象合并的逻辑可以写成一个函数。

const shallowMerge = (target, source) => Object.defineProperties(
target,
Object.getOwnPropertyDescriptors(source)
);

Object.getOwnPropertyDescriptors方法的另一个用处,是配合Object.create方法,将对象属性克隆到一个新对象。这属于浅拷贝。

const clone = Object.create(Object.getPrototypeOf(obj),
Object.getOwnPropertyDescriptors(obj)); // 或者 const shallowClone = (obj) => Object.create(
Object.getPrototypeOf(obj),
Object.getOwnPropertyDescriptors(obj)
);

上面代码会克隆对象obj

另外,Object.getOwnPropertyDescriptors方法可以实现一个对象继承另一个对象。以前,继承另一个对象,常常写成下面这样。

const obj = {
__proto__: prot,
foo: 123,
};

ES6 规定__proto__只有浏览器要部署,其他环境不用部署。如果去除__proto__,上面代码就要改成下面这样。

const obj = Object.create(prot);
obj.foo = 123; // 或者 const obj = Object.assign(
Object.create(prot),
{
foo: 123,
}
);

有了Object.getOwnPropertyDescriptors,我们就有了另一种写法。

const obj = Object.create(
prot,
Object.getOwnPropertyDescriptors({
foo: 123,
})
);

Object.getOwnPropertyDescriptors也可以用来实现 Mixin(混入)模式。

let mix = (object) => ({
with: (...mixins) => mixins.reduce(
(c, mixin) => Object.create(
c, Object.getOwnPropertyDescriptors(mixin)
), object)
}); // multiple mixins example
let a = {a: 'a'};
let b = {b: 'b'};
let c = {c: 'c'};
let d = mix(c).with(a, b); d.c // "c"
d.b // "b"
d.a // "a"

上面代码返回一个新的对象d,代表了对象ab被混入了对象c的操作。

出于完整性的考虑,Object.getOwnPropertyDescriptors进入标准以后,以后还会新增Reflect.getOwnPropertyDescriptors方法。

Object.getOwnPropertyDescriptors()的更多相关文章

  1. JavaScript之Object拆解

    转载烦请注明原文链接: https://github.com/Xing-Chuan/blog/blob/master/JavaScript/JavaScript%E4%B9%8BObject%E6%8 ...

  2. js object 常用方法总结

    Object.assign(target,source1,source2,...) 该方法主要用于对象的合并,将源对象source的所有可枚举属性合并到目标对象target上,此方法只拷贝源对象的自身 ...

  3. js中的Object.defineProperty()和defineProperties()详解

    ECMAS-262第5版在定义只有内部采用的特性时,提供了描述了属性特征的几种属性.ECMAScript对象中目前存在的属性描述符主要有两种,数据描述符(数据属性)和存取描述符(访问器属性),数据描述 ...

  4. 这次彻底理解了Object这个属性

    1.实例化Object对象 实例化Object对象的方式有两种:使用Object构造器和使用对象的字面量.例如: var person1 = { name: '李四' }; var person2 = ...

  5. (80)Wangdao.com第十六天_JavaScript Object 对象的相关方法

    Object 对象的相关方法 Object.getPrototypeOf() 返回参数对象的原型. 这是获取某对象的原型对象的标准方法. var F = function () {}; var f = ...

  6. Object备忘录

    1.Object.assign(target,...source) 方法用于将所有可枚举属性的值从一个或多个源对象复制到目标对象.它将返回目标对象. 2.Object.create()方法创建一个新对 ...

  7. 对象Object

    功能分类                       1. 创建对象 把各对数自身拥有的可枚举属性复制到第一个对象并返回:obj = Object.assign(o1, o2, o3),o1=obj ...

  8. [JS] ECMAScript 6 - Object : compare with c#

    Ref: 对象的扩展 Outline: 属性的简洁表示法 属性名表达式 方法的 name 属性 Object.is() Object.assign() 属性的可枚举性和遍历 Object.getOwn ...

  9. js中Object.defineProperty()和defineProperties()

    在介绍js中Object.defineProperty()和defineProperties()之前,我们了解下js中对象两种属性的类型:数据属性和访问器属性. 数据属性 数据属性包含一个数据的位置, ...

随机推荐

  1. Babel的安装和使用

    安装Node.JS 和 npm,如未安装可参照其他文章 1.创建一个package.json npm init (回车, 一直下一步即可) 安装 Babel npm install --save-de ...

  2. LeetCode中等题(三)

    题目一: 反转从位置 m 到 n 的链表.请使用一趟扫描完成反转. 说明:1 ≤ m ≤ n ≤ 链表长度. 示例: 输入: 1->2->3->4->5->NULL, m ...

  3. JAVA 常用包

    JAVA是以包的形式进行语言结构组织的. 引入这些包的关键词就是 import 下面说说 JAVA常用包有下面的几个 1. java.lang 这个是默认引入的,也是一个最基础的包.其中lang不是中 ...

  4. SpringBoot下配置Druid

    什么是Druid:Druid是阿里发开的一套基于database的监控平台,相对于其他监控来说对于中文的支持更亲民.. 前言:最近这段时间发现项目整体运行响应速度较慢,打算对系统进行深层次的优化(尤其 ...

  5. Markdown中实现折叠代码块

    <details> <summary>展开查看</summary> <pre><code> System.out.println(" ...

  6. 记录6--Java栈堆

    class Person { int age; } public class LearnHeap { public static void main(String args[]){ int a=18; ...

  7. 一个Android音频文本同步的英文有声读物App的开发过程

    转发: http://segmentfault.com/a/1190000003498111 “新概念英语”.“可可英语”.“亚马逊的audible有声书”.“扇贝听力”是我目前所知道的实现英文语音和 ...

  8. nacos集群配置

    一.    环境准备 Nacos 依赖 java环境来运行.如果您是从代码开始构建并运行Nacos,还需要为此配置 Maven环境,请确保是在以下版本环境中安装使用: 64 bit OS,支持 Lin ...

  9. rem与部分手机 字体偏大问题

    原因是部分手机自己设置了巨无霸字体.

  10. nopad++将制表符替换为换行符

    将制表符换位换行