es6新增的代理与反射为开发者提供了拦截并向基本操作嵌入额外行为的能力。具体的说就是可以给目标对象定义一个关联的代理对象,而这个对象可以作为抽象的目标对象使用。在对目标对象的各种操作影响目标对象之前,可以在代理对象中对这些操作加以控制。
9.1.1.创建一个空代理
- 最简单的代理就是空代理:即除了作为一个抽象的目标对象,什么也不做。默认情况下,在代理对象上执行的所有操作都会无障碍地传播到目标对象。因此在任何可以使用目标对象的地方,都可以通过同样的方式来使用与之关联的代理对象。
- 代理是使用proxy构造函数创建的,这个构造函数接收两个参数:(目标对象,处理程序对象),缺少任何一个参数都会抛出TypeError。
- 要创建空代理,可以传入一个简单的对象字面量作为处理程序对象,从而让所有操作都可以抵达目标的对象。
//定义目标对象
const target = {
id:'target'
};
//定义处理程序对象
const handler = {};
//创建代理
const proxy = new Proxy(target,handler);
//访问id属性,访问目标对象和代理对象都是访问一个值
console.log(target.id); //target
console.log(proxy.id); //target
//因为两个对象访问的都是一个值,所有给目标属性赋值会反映在两个对象上
target.id = 'foo';
console.log(target.id); //foo
console.log(proxy.id); //foo
//同理给代理属性赋值也会反映在两个对象上
proxy.id = 'bar';
console.log(target.id); //bar
console.log(proxy.id); //bar
//hasOwnProperty()方法在两个地方都会应用到目标对象
console.log(target.hasOwnProperty('id')); //true
console.log(proxy.hasOwnProperty('id')); //true
//instanceof操作符用来判断一个构造函数的prototype属性所指向的对象是否在另外一个要检测对象的原型链上
//Proxy.prototype是undefined,因此不能使用instanceof操作符
console.log(proxy instanceof target); //Uncaught TypeError: Right-hand side of 'instanceof' is not callable
console.log(target instanceof proxy);; //Uncaught TypeError: Right-hand side of 'instanceof' is not callable
//使用严格相等来区分代理和目标
console.log(target === proxy); //false
9.1.2 定义捕获器
- 使用代理的主要目的就是定义捕获器。捕获器就是在处理程序对象中定义的'基本操作的拦截器'。
- 每个处理程序对象可以包含零个或者多个捕获器,每个捕获器都对应一种基本操作,可以直接或者间接在代理的对象上调用。
- 每次在代理对象上调用这些操作时,代理可以在这些基本操作传播到目标对象之前调用捕获器函数,从而拦截并修改相应的行为。
const target = {
foo:'bar'
}
const handler = {
get(){
return 'handler override';
}
}
const proxy = new Proxy(target,handler);
console.log(target.foo); //bar
console.log(proxy.foo); //handler override
console.log(target['foo']); //bar
console.log(proxy['foo']); //handler override
console.log(Object.create(target)['foo']); //bar
console.log(Object.create(proxy)['foo']); //handler override
当通过代理对象执行get()操作时,就会触发定义的get()捕获器,这个操作可以在js中通过多种形式触发并被get()捕获到
- proxy[property]
- proxy.property
- Object.create(proxy)[property] 只有在代理对象上执行这些操作才会触发捕获器,在目标对象上执行这些操作仍然会产生正常的行为