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,代表了对象a和b被混入了对象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. 遍历 Map 的方式

    今天获取到一个Map 集合,想循环遍历出内容,突然发现忘记如何遍历Map,平时用的太少. Map 集合的内容是 Key , Value 键值对形式存储 第一种是 for 循环遍历 Map<Str ...

  2. Update(Stage4):sparksql:第3节 Dataset (DataFrame) 的基础操作 & 第4节 SparkSQL_聚合操作_连接操作

    8. Dataset (DataFrame) 的基础操作 8.1. 有类型操作 8.2. 无类型转换 8.5. Column 对象 9. 缺失值处理 10. 聚合 11. 连接 8. Dataset ...

  3. LeetCode.62——不同路径

    问题描述: 一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为"Start" ). 机器人每次只能向下或者向右移动一步.机器人试图达到网格的右下角(在下图中标记为 ...

  4. ajax相同url和参数,将不会重复发起请求

    IE浏览器下使用GET发送请求时,如果两次请求的地址和参数相同,在不刷新页面的情况下,浏览器会缓存第一次请求的内容,服务端更新后浏览器仍然显示第一次的内容. 解决办法: 一. GET请求URL后加随机 ...

  5. Jquery+ajax模板

    $.ajax({     url:'',     type:'POST', //GET     async:true,    //或false,是否异步     data:{         name ...

  6. python3升级pip报错ImportError: cannot import name 'main'

    把系统的python版本从默认的2切换到3后,使用pip3安装依赖报错,如下: Traceback (most recent call last): File , in <module> ...

  7. 树莓派安装nextcloud、Seafile

    参考博文:http://bbs.eeworld.com.cn/thread-505579-1-1.html http://blog.sina.com.cn/s/blog_6f55d8210102xia ...

  8. 【转】python装饰器

    什么是装饰器? python装饰器(fuctional decorators)就是用于拓展原来函数功能的一种函数,目的是在不改变原函数名(或类名)的情况下,给函数增加新的功能. 这个函数的特殊之处在于 ...

  9. java代理模式的实现方法

    package com.sample.sping_ireport.cglib; import java.lang.reflect.InvocationHandler; import java.lang ...

  10. Codeforces Round #588 (Div. 2)D(思维,多重集)

    #define HAVE_STRUCT_TIMESPEC#include<bits/stdc++.h>using namespace std;long long a[7007],b[700 ...