ES2018 增加了 Object Spread 操作符的官方支持。Object Spread 操作符和 Object.assign
的一些区别,可以参考这篇文章。
在 JavaScript 执行 Object Spread 操作符的时候,需要进行如下的几步操作:
- 确定对象有哪些自己的属性。原型链上的部分是不会被 Object Spread 操作符接收的,举个例子:
const obj = Object.create(
{ parent: 1 },
{
current: {
enumerable: true,
value: 2,
},
},
);
console.log({ ...obj });
// output => { current: 2 }
- 确定第一步拿到的属性中,有那些是可枚举的(enumerable)。不可枚举的部分,不会被接收,举个例子:
const obj = Object.create(
{ parent: 1 },
{
current: {
enumerable: false,
value: 2,
},
},
);
console.log({ ...obj });
// output => { }
- 分别获取到这些属性的值
根据以上的规则,现在可以考虑这样一个场景:假设需要一个 Proxy 来修改访问对象属性的行为,比如对对象任意属性的取值,都从它的某一个子属性中去拿。例子:
const obj = { key: 'value', child: { key: 'inner-value' } };
const handler = { /* todo */ };
const proxy = new Proxy(obj, handler);
console.log(proxy.key); // => output: inner-value
这里的 handler 并不难写,只需要:
const handler = {
get(target, key) {
return target.child[key];
// or:
// return Reflect.get(target.child, key);
},
};
现在,如果需要 Proxy 也同样可以支持 Object Spread 的功能,那么就需要对 handler
做更多的处理。从上面的分析来看,第一步获取自有属性,需要用到 ownKeys
;第二步获取可枚举属性,需要用到 getOwnPropertyDescriptor
;最后一步获得属性值,依然需要 get
。
代码如下:
const obj = { key: 'value', child: { key: 'inner-value' } };
const handler = {
get(target, key) {
return Reflect.get(target.child, key);
},
ownKeys(target) {
return Reflect.ownKeys(target.child);
},
getOwnPropertyDescriptor(target, key) {
return Reflect.getOwnPropertyDescriptor(target.child, key);
}
};
const proxy = new Proxy(obj, handler);
console.log({ ...proxy }); // => output: { key: 'inner-value' }