Proxy用于修改一些操作的默认行为,等于在语言层面上作出修改,属于“元编程”,即:对编程语言进行编程。
基本用法
Proxy 提供一种可以对外界的访问进行过滤和改写的机制。
ES6原生提供Proxy构造函数,用来生成Proxy实例。
var proxy = new Proxy(target, handler);
Proxy对象的所有用法都是上面这种形式,不同的在于handler
参数的写法。target
参数表示所要拦截的目标对象,handler
参数是一个对象,用来定制拦截行为。
var proxy = new Proxy({}, {
get: function(target, propKey){
return 35;
}
});
console.log(proxy['time']); // 35
上面代码中,在没有Proxy
的介入的情况下,操作本身是访问目标对象的,第二个参数配置对象,对于每一个被代理的操作需要提供一个对象的处理函数,这个函数将拦截对应的操作。在上面的代码中,配置对象有一个get
方法,用来拦截对目标对象属性的访问请求,get
方法的两个参数分别是目标对象和所要访问的属性。由于拦截函数总是返回35
,所以访问任何属性得到35
.
注意,要使
Proxy
起作用,必须针对Proxy
实例进行操作,而不是针对目标进行操作
- 在
handler
没有设置任何拦截,那就等同于直接通向原对象了,没有任何拦截效果。 - 可以将Proxy对象设置到
object.proxy
属性,从而可以在object
对象上调用。
const object = { proxy: new Proxy(target, handler) };
- Proxy实例也可以作为其他对象的原型对象
- 同一个拦截器函数,可以设置多个操作
Proxy 实例的方法
get()
get()
:用于拦截某个属性的读取操作,可以接受三个参数,依次为对象、属性名和p roxy实例本身,最后一个参数为可选。get()
方法是可以继承的。- 如果一个属性不可配置,并且不可写,Proxy 不能修改这个属性,否则通过Proxy 对象访问这个属性会报错。
set()
Set()
方法用来拦截某个属性的赋值操作,可以接受四个参数,依次为目标对象,属性名,属性值和Proxy实例本身(参数可选).- 如果目标对象的某个属性,不可写且不可配置,那么
set
方法将不起作用。 - 在严格模式下,
set
代理如果没有返回true
,就会报错
apply()
方法apply
方法拦截函数的调用,call
和apply
操作
方法apply
可以接受三个参数,分别是目标对象、目标上下文对象(this
)和目标对象的参数数组
var target = function() {return 'this is target'};
var handler = {
apply: function() {
return 'this is proxy';
}
}
var proxy = new Proxy(target, handler);
p() // 'this is proxy'
has()
方法has()
用来拦截HasProperty
操作,即:判断对象是否具有某个属性。典型的操作是in
操作符
方法has()
接受两个参数,分别是目标对象,需要查询的属性名
var handler = {
has (target, key){
if(key[0] === '_'){
return false;
}
return key in target;
}
};
var target = {_prop: 'foo', prop:'foo'};
var proxy = new Proxy(target, handler);
console.log('_proxy' in proxy); // false
has
方法拦截的是HasProperty
操作,而不是HasOwnProperty
操作,has
方法不判断一个属性是对象的自身的属性还是继承属性has
拦截对for...in
循环不生效
Proxy.revocable()
方法Proxy.revocable()
返回一个可取消的Proxy实例
const target = {};
const handler = {};
const {proxy, revoke} = Proxy.revocable(target, handler);
proxy.foo = 123;
console.log(proxy.foo); // 123
revoke();
console.log(proxy.foo); // TypeError
方法Proxy.revocable()
返回一个对象,这个对象的proxy
属性是Proxy
实例,revoke
属性是一个函数,可以取消Proxy
实例。
使用场景
目标对象不允许直接访问,必须通过代理访问,一旦访问结束就收回代理,不允许再次访问
this问题
Proxy可以代理针对目标对象的访问,但不是目标对象的透明代理,即:不做任何拦截的情况下,也无法保证与目标对象的行为一致。主要是因为,Proxy代理的情况下,目标对象内部的this
关键字会指向Proxy 代理,有些原生对象的内部属性,只有痛过正确的this
才能拿到,所以,此时Proxy无法代理这些原生对象的属性。
Web服务的客户端
Proxy 对象可以拦截目标对象的任意属性,使得Proxy非常适合写Web服务的客户端。
function createWebService(baseUrl){
return new Proxy({},{
get(target, propKey,reveiver){
return () => httpGet(baseUrl + '/' + propKey)
}
});
}
备注:本文是自己学习阮一峰老师的《ECMAScript 6 入门》所做的笔记,大部分例子来源于此书。