ES6的代理对象Proxy
Proxy用于修改某些对象操作的默认行为,可以理解成在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,可以对外界的访问进行过滤和改写
Proxy(target,handlers):创建代理对象
target 要拦截的目标对象
handlers 处理器对象,用来定制拦截行为
Proxy支持的拦截操作一共13种
以下函数中propKey为键名,receiver为代理对象本身,可以省略该参数
get(target, propKey, receiver):拦截对象属性的读取
set(target, propKey, value, receiver):拦截对象属性的设置,返回一个布尔值
has(target, propKey):拦截key in proxy的操作,返回一个布尔值
deleteProperty(target, propKey):拦截delete操作,返回一个布尔值。
ownKeys(target):
拦截
Object.getOwnPropertyNames(proxy)、
Object.getOwnPropertySymbols(proxy)、
Object.keys(proxy)、
for...in循环
返回一个数组
该方法返回目标对象所有自身的属性的属性名
而Object.keys()的返回结果仅包括自身的可遍历属性名
getOwnPropertyDescriptor(target, propKey)
拦截
Object.getOwnPropertyDescriptor(proxy, propKey)
返回属性的描述对象
defineProperty(target, propKey, propDesc)
拦截
Object.defineProperty(proxy, propKey, propDesc)、
Object.defineProperties(proxy, propDescs)
返回一个布尔值
preventExtensions(target):拦截Object.preventExtensions(proxy),返回一个布尔值
getPrototypeOf(target):拦截Object.getPrototypeOf(proxy),返回一个对象
isExtensible(target):拦截Object.isExtensible(proxy),返回一个布尔值
setPrototypeOf(target, proto):拦截Object.setPrototypeOf(proxy, proto),返回一个布尔值
如果目标对象是函数,那么还有两种额外操作可以拦截。
apply(target, object, args):拦截Proxy实例作为函数调用的操作
如proxy(...args)、proxy.call(object, ...args)、proxy.apply(...)
construct(target, args):拦截 Proxy 实例作为构造函数调用的操作,如new proxy(...args)
应用示例:数组支持负数索引
let arr = [0,1,2,3,4,5,6];
let proxy = new Proxy(
arr,
{
get:function(target,key){
let index = +key;
// 将key转换为数字
if (index>0){
return target[index];
}else{
return target[target.length + index];
}
}
}
);
Proxy.revocable(target, handler):用来创建一个可取消的Proxy
let {proxy, revo} = Proxy.revocable({}, {});
proxy.foo = 123;
proxy.foo // 123
revo();
proxy.foo // TypeError: Revoked
Proxy.revocable()的一个使用场景是,目标对象不允许直接访问,必须通过代理访问,一旦访问结束,就收回代理权,不允许再次访问
Proxy中的this问题
一旦proxy代理target,target.func()内部的this就是指向proxy,而不是target
所以,虽然proxy没有做任何拦截,target.func()和proxy.func()返回不一样的结果