Object Spread and Proxy

JavaScript

ES2018 增加了 Object Spread 操作符的官方支持。Object Spread 操作符和 Object.assign 的一些区别,可以参考这篇文章

在 JavaScript 执行 Object Spread 操作符的时候,需要进行如下的几步操作:

  1. 确定对象有哪些自己的属性。原型链上的部分是不会被 Object Spread 操作符接收的,举个例子:
const obj = Object.create(
  { parent: 1 },
  {
    current: {
      enumerable: true,
      value: 2,
    },
  },
);
console.log({ ...obj });
// output => { current: 2 }
  1. 确定第一步拿到的属性中,有那些是可枚举的(enumerable)。不可枚举的部分,不会被接收,举个例子:
const obj = Object.create(
  { parent: 1 },
  {
    current: {
      enumerable: false,
      value: 2,
    },
  },
);
console.log({ ...obj });
// output => { }
  1. 分别获取到这些属性的值

根据以上的规则,现在可以考虑这样一个场景:假设需要一个 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' }