认识一下ES6的Reflect和Proxy

Reflect

Reflect要替代Object的很多方法, 将Object对象一些明显属于言内部的方法放到了Reflect对象上,有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)

 Reflect所有方法的第一个参数都必须是对象,不能是简单数据类型,比如1,true; 

Reflect.apply方法等同于Function.prototype.apply.call(func, thisArg, args),用于绑定this对象后执行给定函数.
Function.prototype.apply.call <===> Reflect.apply

Reflect.getPrototypeOfObject.getPrototypeOf的一个区别是,如果参数不是对象,Object.getPrototypeOf会将这个参数转为对象,然后再运行,而Reflect.getPrototypeOf会报错。

Proxy

Proxy代理可以对对象(不可以为一个简单数据类型比如1, true, 'string'设置proxy.)的某一些行为进行接截,利用这一点,可以对外界的访问进行过滤和改写。

Proxy的构造方法,需要传递两个参数,第一个参数是要进行过滤拦截的对象,第二参数也是一个对象,这个对象指明对哪些行为进行接截

const obj ={
  name:'',age:'18',
  get showName() {return `${this.name}年龄${this.age}`}  
}

const proxyOpr = {
 get: function(target, key, receiver){
     console.log(`getting ${key}`);
      return Reflect.get(target, key, receiver);
 },
  set: function(target, key, value, receiver){
    console.log(`setting ${key} as '${value}'`);
     return Reflect.set(target, key, value, receiver); 
  } 
}

const proxy = new Proxy(obj, proxyOpr);
proxy.name='test proxy';
console.log(proxy.showName);

// setting name as 'test proxy'

// getting showName
// getting name
// getting age
// test proxy年龄18

对obj的取值及赋值操作都被拦截并添加了一个日志打印。

注意点:

1 get和apply过滤都存在时,会走get过滤。

2 生成的代理对象会取得this.

3 可以用Proxy.revocable来取消代理

let target = {};
let handler = {};

let {proxy, revoke} = Proxy.revocable(target, handler);

proxy.foo = 123;
proxy.foo // 123

revoke(); //取消代理
proxy.foo //TypeError: Revoked

 new Proxy()产生的对象的数据类型是和目标对象一值的,即目标对象是funtion,它的proxy也为function

const proxy1 = new Proxy(function(i, j){return i+j;},
{
  apply: function(target, thisBinding, args){
    console.log(args);
    return Reflect.apply(target, thisBinding, args); //切记写return 
  }
})
const t = proxy1(1, 2);
console.log(t);
typeof proxy1
// [1,2]
// 3
// "function"

 Proxy实例也可以作为其他对象的原型对象

var proxy = new Proxy({}, {
  get: function(target, property) {
    return 35;
  }
});

var obj ={name:'tt'};
Reflect.setPrototypeOf(obj,proxy)

obj.name // tt
obj.age //35

  obj对象本身没有age属性,所以根据原型链,会在proxy对象上读取该属性,导致被拦截.而obj自身具有属性,读取时不会被拦截。

 

代理的出现可以让目标对象只关注于自己的行为,与外界的沟通都可以放到proxy里来完成。比如说猫叫老鼠跑。其实猫可以不知道有没有老鼠或是别的动物,它只实现自己的叫就可以了。到底是谁跑可以交给猫的代理来完成。代理里拦截到猫叫,就可以加入猫食物链下所有动物都跑的行为。

Reflect和Proxy里可以拦截的方法是一一对应的。只要是Proxy对象的方法,就能在Reflect对象上找到对应的方法。

冥冥中觉得js的代理跟spring里的代理有些类似,可以学习对比一下。

 

上一篇:设计模式之动态代理(JDK代理)


下一篇:Java反射机制大神必学系列之 ,高级与低级的差别在哪里?