Proxy 用于修改某些操做的默认行为,等同于在语言层面作出修改,因此属于一种『元编程』即对编程语言进行编程。
Proxy 是在目标对象以前架设一层『拦截』,外部对对象的访问,都须要通过该层拦截。所以在拦截中对外界的访问进行过滤和改写。
在Es6 中 提供了原生的 Proxy 构造函数,能够用来生成 Proxy实例。编程
let proxy = new Proxy(target, handler)
Proxy 对象的全部用法,都是上面的形式,不一样的只是handler参数的写法。其中new Proxy() 表示生成一个 Proxy实例,target 参数表示全部拦截的目标对象, handler 参数也是一个对象,用来定制拦截行为。以下:segmentfault
let proxy = new Proxy({}, { get: function(target, property) { return 35 } }) proxy.time // 35 proxy.name // 35 proxy.title // 35
解读:数组
在上面中,做为构造函数,Proxy接受两个参数。第一个参数即所要代理的目标对象,若是没有 Proxy的介入,操做原来要访问的就是这个对象。第二个参数是一个配置对象,用来对每一个代理对象的操做,提供具体的函数和拦截操做。上述代码中有一个 get 函数,用来拦截对目标对象属性的访问请求。app
另外,要使 Proxy起做用,必须针对 Proxy 实例进行操做,而不是针对目标对象进行操做。编程语言
若是 handler 没有设置任何拦截,那就等同于直接通向原对象。以下:函数
let target = {} let handler = {} let proxy = new Proxy(target, handler) proxy.a = 'b' target.a = 'b'
对于上面的例子,咱们能够讲Proxy对象,设置到 object.proxy属性,从而能够在object对象上调用。this
let object = {proxy: new Proxy(target, handler)}
Proxy 实例也能够做为其余对象的原型对象。spa
let proxy = new Proxy({}, { get: function(target, property) { retrun 35 } }) let obj = Object.create(proxy) obj.time // 35 另外同一个拦截器,能够设置多个拦截操做。
经常使用的Proxy支持的拦截操做以下:代理
get 方法用于拦截某个属性的读取操做,能够接受三个参数,依次为目标对象、属性名和proxy实例自己,最后一个参数可选。
let p = { name: '李四' } let proxy = new Proxy(p, { get: function(target, property) { if (property in target) { retrun target[property] } else { console.log('报错') } } }) proxy.name // '李四' proxy.age // '报错'
注意点code
set 方法用来拦截某个属性的赋值操做,能够接受四个参数,依次为目标对象、属性名、属性值和Proxy实例自己,最后一个可选
let v = { set: function(obj, prop, value) { if (prop === 'age') { if(!Number.isInteger(value)) { console.log('报错') } if(value > 200) { console.log('成功') } obj[prop] = value } } } let p = new Proxy({}, v) p.age = 100 p.age // 100 p.age = 'n' p.age // 报错
利用set方法,能够数据绑定,即每当对象发生变化时,会自动更新Dom
若是目标对象自身的某个属性,不可写且不可配置,那么Set 方法将不起做用。
1.4 apply()
apply 方法拦截函数的调用、call 和 apply操做。它能够接受三个参数,分别时目标对象、目标对象的上下文对象(this)和目标对象的参数数组。
let h = { apply(target, ctx, args) { return Reflect.apply(...arguments) } } let target = function() {return 'haha') let h = { apply: function() { return 'heihei' } } let p = new Proxy(taraget, h) p() // 'heihei'
has 方法用来拦截 HasProperty 操做, 即判断对象是否具备某个属性时,这个方法会生效。
has 方法能够接受两个参数,分别时目标对象、须要查询的属性名。
注意:has 方法拦截的时 HasProperty操做,而不是HasOwnProperty操做,即has 方法不判断一个属性是对象自身的属性,仍是继承的属性。
construct 方法用于拦截 new命令,下面是拦截对象的写法
let h = { construct(target, args, newTarget) { retrun new target(...args) } } target: 目标对象 args: 构造函数的参数对象 newTarget: 创造实例对象时,new命令做用的构造函数
deleteProperty 方法用于拦截 delete 操做,若是这个方法抛出错误或者返回false,当前属性就没法被delete命令删除。
虽然 Proxy 能够代理针对目标对象的访问,但它不是目标对象的透明代理,即不作任何拦截的状况下,也没法保证目标对象的行为一致。主要缘由就是在Proxy代理的状况下,目标对象内部的this关键字会指向Proxy代理