Proxy是ECMAScript新增的api。可以为开发者提供拦截并向基本操作嵌入额外的行为的能力。
Proxy可以给目标定义一个相关联的代理对象,而这个代理对象可以作为抽象的目标对象来使用。在对目标对象的各种操作影响目标对象之前,可以在代理对象中对这些操作加以控制。
大部分现代浏览器均已支持,支持用户的比例已经非常接近Object: defineProperty
96.31% Proxy 97.33% Object: defineProperty
我认为Proxy的精髓就是捕获器。
使用代理的主要目的是可以定义捕获器(trap)
。捕获器
就是在处理程序对象中定义的“基本操作的拦截器”。每个处理程程序对象可以包含零个或多个捕获器,每个捕获器都对应一种基本操作,可以直接或间接在代理对象上调用。每次在代理对象上调用这些基本操作时,代理可以在这些操作传播到目标对象之前先调用捕获器函数,从而拦截并修改相应的行为。
捕获器(trap)
是从操作系统中借用的概念。在操作系统中,捕获器是程序流中的一个同步中断,可以暂停程序流,转而执行一段子例程,之后再返回原始程序流。
以最常用的set为例:
set()捕获器会在设置属性值的操作中被调用。对应的反射API方法为Reflect.set()。
const myTarget ={}
const proxy = new Proxy (myTarget,{
set(target,property,value,receiver){
console.log ('set ()')
return Reflect.set (..arguments)
}
});
proxy.foo ='bar';
1.返回值
返回true表示成功;返回false表示失败,严格模式下会抛出TypeError。
2.拦截的操作
3.捕获器处理程序参数
如果target.property不可写且不可配置,则不能修改目标属性的值。
4.捕获器不变式
如果target.property不可写且不可配置,则不可修改目标属性的值。
如果target.property不可配置且[[set]]特性为undefined,则不能修改目标属性的值。
在严格模式下,处理程序中返回false会抛出TypeError。
代理的捕获器
可以捕获13种不同的基本操作。这些操作有各自不同的反射API方法、参数、关联ECMAScript操作和不变式。
下面列出几个可捕获的,常用的基本操作。
get()捕获器会在获取属性值的操作中被调用。对应的反射AP方法为Ref1ect.get()。
const myTarget ={}
const proxy = new Proxy (myTarget,{
get(target,property,receiver){
console.log ('get ()')
return Reflect.get(..arguments)
}
});
proxy.foo;
1.返回值
返回值无限制。
2.拦截的操作
3.捕获器处理程序参数
如果target.property不可写且不可配置,则不能修改目标属性的值。
4.捕获器不变式
如果target.property不可写且不可配置,则处理程序返回的值必须与target.property匹配。
如果target.property不可配置且[[Get]]特性为undefined,处理程序的返回值也必须是undefined。
const myTarget ={}
const proxy = new Proxy (myTarget,{
has(target,property){
console.log ('has ()')
return Reflect.has(..arguments)
}
});
'foo'in proxy;
1.返回值
has()必须返回布尔值,表示属性是否存在。返回非布尔值会被转型为布尔值。
2.拦截的操作
3.捕获器处理程序参数
4.捕获器不变式
如果target.property存在且不可配置,则处理程序必须返回true。
如果target.property存在且目标对象不可扩展,则处理程序必须返回true。
apply()捕获器会在调用函数时中被调用。对应的反射AP方法为Retlect,apply()。
const myTarget =() => {}
const proxy = new Proxy (myTarget,{
apply(target,thisArg,...argumentsList){
console.log ('apply()')
return Reflect.apply(...arguments)
}
});
proxy();
construct()捕获器会在new操作符中被调用。对应的反射API方法为Reflect.construct()。
const myTarget =() => {}
const proxy = new Proxy (myTarget,{
apply(target,argumentsList,newTarget){
console.log ('construct()')
return Reflect.construct(...arguments)
}
});
new proxy();
1.返回值
construct()必须返回一个对象。
2.拦截的操作
3.捕获器处理程序参数
4.捕获器不变式
target必须可以用作构造函数。
参考: 《JavaScript高级程序设计》 https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Proxy