# Proxy

Proxy 用于修改某些操作默认行为,等同于在语言层面修,对编程语言进行编程,听说下版本的vue就会用Proxy,替代Object.defineProperty
可以理解成,在目标对象之前设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截

let proxy = new Proxy(target, handler);
//target参数表示所要拦截的目标对象
//handler参数也是一个对象,用来定制拦截行为
let person = {
  name: "张三"
};
let proxy = new Proxy(person, {
  get: function(target, property) {
    if (property in target) {
      return target[property];
    } else {
      throw new ReferenceError("Property \"" + property + "\" does not exist.");
    }
  }
});
proxy.name // "张三"
proxy.age // 抛出一个错误

拦截操作共13种,常用的如下:

  • get(target, propKey, receiver):拦截对象属性的读取
  • set(target, propKey, value, receiver):拦截对象属性的设置,返回布尔值
  • has(target, propKey):拦截propKey in proxy的操作,返回一个布尔值
  • deleteProperty(target, propKey):拦截delete proxy[propKey]的操作,返回一个布尔值。
  • defineProperty(target, propKey, propDesc):拦截Object.defineProperty(proxy, propKey, propDesc)Object.defineProperties(proxy, propDescs),返回一个布尔值。
  • construct(target, args):拦截 Proxy 实例作为构造函数调用的操作,比如new proxy(...args)
  • apply(target, object, args):拦截 Proxy 实例作为函数调用的操作,比如proxy(...args)proxy.call(object, ...args)proxy.apply(...)

注意点:在 Proxy 代理的情况下,目标对象内部的this关键字会指向 Proxy 代理。有些原生对象的内部属性,只有通过正确的this才能拿到,所以 Proxy 也无法代理这些原生对象的属性。如new Date()

# Reflect

Reflect对象与Proxy对象一样,操作对象的新API

  • 将Object对象上方法放到Reflect上
  • 修改Object方法的返回结果,使其更合理,
  • 并让Object操作变为函数行为

Reflect对象的方法与Proxy对象的方法一一对应,一共13个

  • Reflect.apply(target, thisArg, args)
  • Reflect.construct(target, args)
  • Reflect.get(target, name, receiver)
  • Reflect.set(target, name, value, receiver)
  • Reflect.defineProperty(target, name, desc)
  • Reflect.deleteProperty(target, name)
  • Reflect.has(target, name)
  • Reflect.ownKeys(target)
  • Reflect.isExtensible(target)
  • Reflect.preventExtensions(target)
  • Reflect.getOwnPropertyDescriptor(target, name)
  • Reflect.getPrototypeOf(target)
  • Reflect.setPrototypeOf(target, prototype)
let obj = {
  foo: 1,
  bar: 2,
  get baz() {
    return this.foo + this.bar;
  },
}

Reflect.get(obj, 'foo') // 1
Reflect.set(obj, 'bar', 3)//3
// 旧写法
'foo' in obj // true
Reflect.has(obj, 'foo') // true
// 删除 旧写法
delete obj.foo;
// 新写法
Reflect.deleteProperty(obj, 'foo');
function MyDate() {
  /*…*/
}
// 旧写法
Object.defineProperty(MyDate, 'now', {
  value: () => Date.now()
});
// 新写法
Reflect.defineProperty(MyDate, 'now', {
  value: () => Date.now()
});
//实现观察者模式Observer mode,函数自动观察数据对象
const queuedObservers = new Set();

const observe = fn => queuedObservers.add(fn);
const observable = obj => new Proxy(obj, {set});

function set(target, key, value, receiver) {
  const result = Reflect.set(target, key, value, receiver);
  queuedObservers.forEach(observer => observer());
  return result;
}