代理(Proxy)是一种可以拦截并改变底层js引擎操作的包装器。它在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。
创建一个简单的代理
用proxy构造函数创建代理需要传入两个参数:target(目标)和handler(处理程序)。
let target = {};
let proxy = new Proxy(target, {});
proxy.name = 'dudu';
console.log(proxy.name);
console.log(target.name);
target.name = 'lala';
console.log(proxy.name);
console.log(target.name);
这个示例中的代理将所有的操作直接转发到目标,将'dudu'赋值给proxy.name属性时会在target上创建name,代理只是简单的将操作转发给了target,代理本身是不会储存这个属性。
使用set拦截写入属性的操作
问题:一个对象target,它的所有属性的值必须是数字,如果不是数字必须抛出错误。
let target = {
name: 'dudu';
};
let proxy = new Proxy(target, {
set(trapTarget, key, value, receiver) {
// 忽略不希望收到影响的已有元素
if (!trapTarget.hasOwnProperty(key)) {
if (isNaN(value)) {
throw new TypeError("属性必须是数字");
}
}
// 添加属性
return Reflect.set(trapTarget, key, value, receiver)
}
});
在该段代码中,我们定义了一个set陷阱来覆写设置属性值得默认特性。set陷阱接受四个参数:
-
trapTarget
用于接收属性(代理的目标)的对象 -
key
要写入的属性键值 -
value
被写入的属性值 -
receiver
操作发生的对象(代理)
使用get拦截读取属性的操作
问题:如果一个属性不存在,让这个对象抛出错误
var person = {
name: "pangpang"
};
var proxy = new Proxy(person, {
get: function(target, property) {
if (property in target) {
return target[property];
} else {
throw new ReferenceError("Property \"" + property + "\" does not exist.");
}
}
});
proxy.name // "pangpang"
proxy.age // 抛出一个错误
除了set与get外,还有很多其他的代理陷阱,每个代理陷阱都可以复写js对象的一些内建特性,这里就不一一写出来了。
原型代理陷阱
ES6新增了方法Object.setPrototypeOf()
用来改变任意制定对象的原型,以及返回指定对象原型的Object.getPrototypeOf()
。通过代理中的setPrototypeOf与getPrototypeOf可以拦截这两个方法的执行过程。在这两种情况下,Object上的方法会调用代理中的同名陷阱来改变方法的行为。
网友评论