本篇目录
Proxy数组
常见的Proxy拦截操做app
Reflect函数
猪八戒去高老庄找高翠兰,结果高小姐是孙悟空变的,在这个场景中,对于猪八戒来讲,孙悟空能够算是高小姐的一个代理,在长相上来讲,他们是一致的。猪八戒只能访问到被孙悟空假扮的高小姐,却见不到真正的高小姐。
在上面的场景中,孙悟空就相似于咱们今天要讲的ES6中的Proxy,它是一种“代理”,或者能够称之为“拦截”。外界在对一个对象进行访问的时候,都先必须经过这层拦截,才能进行访问。而这个拦截的过程当中能够对外界的访问进行过滤和改写。this
咱们先来看一个例子:设计
let obj = new Proxy({}, { 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}!`); return Reflect.set(target, key, value, receiver); } });
在上面这个例子中,咱们经过Proxy对一个空对象进行了拦截,从新定义了对象属性的读取(get
)和设置(set
)行为。代理
ES6 原生提供 Proxy 构造函数,用来生成 Proxy 实例。code
let proxy = new Proxy(target, handler);
其中,new Proxy()表示生成一个Proxy实例,target参数表示所要拦截的目标对象,handler参数也是一个对象,用来定制拦截行为。server
注意,要使得Proxy起做用,必须针对Proxy实例(上例是proxy对象)进行操做,而不是针对目标对象(上例是空对象)进行操做。
若是handler没有设置任何拦截,那就等同于直接通向原对象。对象
let target = {}; let handler = {}; let proxy = new Proxy(target, handler); proxy.a = 'b'; target.a // "b"
Proxy支持的拦截操做有:事件
下面咱们就几个常见的拦截进行举例说明。
默认一个对象:
let obj={ time:'2017-03-11', name:'net', _r:123 };
// 拦截对象属性的读取 get(target,key){ return target[key].replace('2017','2018') }
// 拦截对象设置属性 set(target,key,value){ if(key==='name'){ return target[key]=value; }else{ return target[key]; } }
// 拦截key in object操做 has(target,key){ if(key==='name'){ return target[key] }else{ return false; } }
// 拦截delete deleteProperty(target,key){ if(key.indexOf('_')>-1){ delete target[key]; return true; }else{ return target[key] } }
// 拦截Object.keys,Object.getOwnPropertySymbols,Object.getOwnPropertyNames ownKeys(target){ return Object.keys(target).filter(item=>item!='time') }
Proxy.revocable方法返回一个能够取消的Proxy实例
let target = {}; let handler = {}; let {proxy, revoke} = Proxy.revocable(target, handler); proxy.foo = 123; proxy.foo // 123 revoke(); proxy.foo // TypeError: Revoked
Proxy.revocable方法返回一个对象,该对象的proxy属性是Proxy实例,revoke属性是一个函数,能够取消Proxy实例。上面代码中,当执行revoke函数以后,再访问Proxy实例,就会抛出一个错误。
Proxy.revocable的一个使用场景是,目标对象不容许直接访问,必须经过代理访问,一旦访问结束,就收回代理权,不容许再次访问。
虽然 Proxy 能够代理针对目标对象的访问,但它不是目标对象的透明代理,即不作任何拦截的状况下,也没法保证与目标对象的行为一致。主要缘由就是在 Proxy 代理的状况下,目标对象内部的this关键字会指向 Proxy 代理。
const target = { m: function () { console.log(this === proxy); } }; const handler = {}; const proxy = new Proxy(target, handler); target.m() // false proxy.m() // true
因此在一些状况下,有些对象的属性只能经过正确的this才能拿到时,因为this指向的变化,致使Proxy没法代理目标对象。
const target = new Date(); const handler = {}; const proxy = new Proxy(target, handler); proxy.getDate(); // TypeError: this is not a Date object.
为何咱们要一块儿来讲Reflect呢?Reflect对象与Proxy对象同样,也是 ES6 为了操做对象而提供的新 API。
(1) 将Object对象的一些明显属于语言内部的方法(好比Object.defineProperty),放到Reflect对象上。现阶段,某些方法同时在Object和Reflect对象上部署,将来的新方法将只部署在Reflect对象上。也就是说,从Reflect对象上能够拿到语言内部的方法。
(2) 修改某些Object方法的返回结果,让其变得更合理。好比,Object.defineProperty(obj, name, desc)在没法定义属性时,会抛出一个错误,而Reflect.defineProperty(obj, name, desc)则会返回false。
// 老写法 try { Object.defineProperty(target, property, attributes); // success } catch (e) { // failure } // 新写法 if (Reflect.defineProperty(target, property, attributes)) { // success } else { // failure }
(3) 让Object操做都变成函数行为。某些Object操做是命令式,好比name in obj和delete obj[name],而Reflect.has(obj, name)和Reflect.deleteProperty(obj, name)让它们变成了函数行为。
// 老写法 'assign' in Object // true // 新写法 Reflect.has(Object, 'assign') // true
(4)Reflect对象的方法与Proxy对象的方法一一对应,只要是Proxy对象的方法,就能在Reflect对象上找到对应的方法。这就让Proxy对象能够方便地调用对应的Reflect方法,完成默认行为,做为修改行为的基础。也就是说,无论Proxy怎么修改默认行为,你总能够在Reflect上获取默认行为。
Proxy(target, { set: function(target, name, value, receiver) { var success = Reflect.set(target,name, value, receiver); if (success) { log('property ' + name + ' on ' + target + ' set to ' + value); } return success; } });
Reflect与ES5的Object有点相似,包含了对象语言内部的方法,Reflect也有13种方法,与proxy中的方法一一对应。
Proxy至关于去修改设置对象的属性行为,而Reflect则是获取对象的这些行为。
相关使用你们参照Object和Proxy的使用便可,再也不一一赘述。
观察者模式(Observer mode)指的是函数自动观察数据对象,一旦对象有变化,函数就会自动执行。
在咱们以前的开发过程当中,咱们若是想要实现观察者模式的话,咱们可能须要进行事件绑定和触发来实现。
Event.listen('changeName', name => console.log(name)) Event.trigger('changeName', name )
可是在ES6中,咱们能够经过使用Proxy和Reflect来实现这个目的
//添加观察者 const queuedObservers = new Set(); const observe = fn => queuedObservers.add(fn); //proxy 的set 方法 function set(target, key, value, receiver) { const result = Reflect.set(target, key, value, receiver); queuedObservers.forEach(observer => observer()); return result; } //建立proxy代理 const observable = obj => new Proxy(obj, {set}); //被观察的 对象 const person = observable({ name: '张三', age: 20 }); function print() { console.log(`${person.name}, ${person.age}`) } function print2() { console.log(`我是二号观察者:${person.name}, ${person.age}`) } //添加观察者 observe(print); observe(print2); person.name = '李四'; // 输出 // 李四, 20 // 我是二号观察者:李四, 20
Proxy和Reflect都是ES6中针对对象新增的方法,Proxy修改设置对象的属性行为,而Reflect则是获取对象的这些行为。