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.getPrototypeOf和Object.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 // 123revoke(); //取消代理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 // ttobj.age //35
obj对象本身没有age属性,所以根据原型链,会在proxy对象上读取该属性,导致被拦截.而obj自身具有属性,读取时不会被拦截。
代理的出现可以让目标对象只关注于自己的行为,与外界的沟通都可以放到proxy里来完成。比如说猫叫老鼠跑。其实猫可以不知道有没有老鼠或是别的动物,它只实现自己的叫就可以了。到底是谁跑可以交给猫的代理来完成。代理里拦截到猫叫,就可以加入猫食物链下所有动物都跑的行为。
Reflect和Proxy里可以拦截的方法是一一对应的。只要是Proxy
对象的方法,就能在Reflect
对象上找到对应的方法。
冥冥中觉得js的代理跟spring里的代理有些类似,可以学习对比一下。