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 入门》所做的笔记,大部分例子来源于此书。
本文详细介绍了ES6中的Proxy,它能修改对象操作的默认行为,实现元编程。Proxy通过构造函数生成实例,可以拦截get、set、apply、has等操作。get方法拦截属性读取,set方法拦截属性赋值,apply拦截函数调用,has拦截操作。Proxy.revocable()返回可取消的Proxy实例,适用于临时访问控制。然而,由于this指向问题,Proxy并非目标对象的完全透明代理,尤其在处理原生对象时。Proxy在Web服务客户端的应用非常广泛。
3752

被折叠的 条评论
为什么被折叠?



