上一个博客提到了Object.getOwnPropertyDescriptor方法会返回某个对象属性的描述对象。ES2017引入了Object.getOwnPropertyDescriptors方法。返回值为对象所有自身属性(非继承属性)的描述对象。
const obj = {
a : 1,
foo(){},
get bar(){
return 1;
}
}
console.log(Object.getOwnPropertyDescriptors(obj));
Object.getOwnPropertyDescriptors方法的实现原理很简单
const getOwnPropertyDescriptors = (obj) => {
let 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 target = {};
Object.assign(target,source);
console.log(target); //{ foo : undefined}
console.log(Object.getOwnPropertyDescriptor(target,"foo"));
上面代码中,source对象的foo属性的值是一个赋值函数,Object.assign方法将这个属性拷贝给target1对象,结果该属性的值变成了undefined。这是因为Object.assign方法总是拷贝一个属性的值,而不会拷贝它背后的赋值方法或取值方法。 这时,Object.getOwnPropertyDescriptors方法配合Object.defineProperties方法,就可以实现正确拷贝。
//Object.getOwnPropertyDescriptors拷贝对象方法
const shallMerge = (target,source) => Object.defineProperties(target,Object.getOwnPropertyDescriptors(source));
Object.getOwnPropertyDescriptors方法的另一个用处,是配合Object.create方法,将对象属性克隆到一个新对象上面。这属于浅拷贝。
//getPrototypeOf方法是读取该对象的__proto__
const shallowClone = (obj) => Object.create(Object.getPrototypeOf(obj),Object.getOwnPropertyDescriptors(obj));
let obj = {
a : 1,
}
console.log(shallowClone(obj));
另外,Object.getOwnPropertyDescriptors方法可以实现一个对象继承另一个对象。ES6 规定__proto__只有浏览器要部署,其他环境不用部署。
const shallowExtend = (target,source) => Object.create(target,Object.getOwnPropertyDescriptors(source));
Object.getOwnPropertyDescriptors也可以用来实现Mixin(混入模式)。
const mix = (object) => ({
with : (...mixins) => mixins.reduce(
(c,mixin) => Object.create(
c,Object.getOwnPropertyDescriptors(mixin)
),object),
})
let a = {a : "a"};
let b = {b : "b"};
let c = {c : "c"};
let d = mix(c).with(a,b);
for(let key in d){
console.log(key); //b a c
}
//上面代码b继承了a,把c对象混入了原型a上