Proxy
什么是 Proxy ?
proxy是javascript的一个内置对象。proxy对象允许你为另一个对象创建代理,代理可以拦截并重新定义该对象的基本操作。
提示
关于proxy更详细的介绍可以查阅官方文档
构造函数的参数
其构造函数有两个参数:
target: 被代理的原始对象handler: 一个将拦截操作以及重新定义操作的对象。
使用方法
javascript
const target = {
message1: "hello",
message2: "everyone",
};
const handler = {
get(target, prop, receiver){
return '不告诉你'
}
};
const proxy = new Proxy(target, handler);
console.log(proxy.message1) // 不告诉你javascript
const target = {
message1: "hello",
message2: "everyone",
};
const handler = {
get(target, prop, receiver){
console.log('target: ',target)
console.log('prop: ', prop)
console.log('receiver: ', receiver)
console.log('receiver是target吗?', target === receiver)
return Reflect.get(target, prop, receiver)
}
};
const proxy = new Proxy(target, handler);
console.log(proxy.message1)
/**
target: { message1: 'hello', message2: 'everyone' }
prop: message1
receiver: { message1: 'hello', message2: 'everyone' }
receiver是target吗? false
hello
*/target是被代理的那个对象,prop是要访问的属性名,receiver是访问者。通常是proxy。
输出是receiver和target长得一样,让你觉得proxy和target一样。但是他们不是同一个东西
这里我们提供了get()处理程序的实现,它拦截了访问目标属性的尝试。
一个注意点
其实,上面的例子有一个小点没有说,返回的时候不能使用target[prop],要使用reflect。若直接target[prop]的话,在target里面访问函数时,this不是代理者,而是target。这可能会出现一些问题。下列代码提供解释:
javascript
const obj = {
firstName: "张",
lastName: "三",
get fullName() {
console.log("getter 执行, this是obj吗? ", this === obj);
return this.firstName + this.lastName;
}
};
const proxy = new Proxy(obj, {
get(target, prop,receiver) {
console.log("检测到读取:", prop);
return Reflect.get(target, prop, receiver);
}
});
console.log(proxy.fullName);
/**
检测到读取: fullName
getter 执行, this是obj吗? false
检测到读取: firstName
检测到读取: lastName
张三
*/上面的代码,执行get fullName时,this里面依旧是proxy,会递归触发proxy.firstName以及proxy.lastName。这是我们想要的。如果不使用Reflect.get,而是target[prop]的话。。。
javascript
const obj = {
firstName: "张",
lastName: "三",
get fullName() {
console.log("getter 执行, this是obj吗? ", this === obj);
return this.firstName + this.lastName;
}
};
const proxy = new Proxy(obj, {
get(target, key,receiver) {
console.log("检测到读取:", key);
return target[prop]
}
});
console.log(proxy.fullName);
/**
检测到读取: fullName
getter 执行, this是obj吗? true
张三
*/上面的代码说明,读取firstName与lastName时直接绕过了Proxy,这不是我们想要的!所以要使用Reflect。
handler 还有哪些方法?
handler 对象共支持 13 个捕获器(trap),可以拦截几乎所有对目标对象的操作:
属性读写
get(target, prop, receiver)— 拦截属性读取set(target, prop, value, receiver)— 拦截属性设置,必须返回true/false表示成功或失败
属性存在与删除
has(target, prop)— 拦截prop in target操作符deleteProperty(target, prop)— 拦截delete target[prop]操作
函数相关
apply(target, thisArg, argumentsList)— 拦截函数调用target(...args),注意 target 必须是函数construct(target, argumentsList, newTarget)— 拦截new target(...args)操作
原型相关
getPrototypeOf(target)— 拦截Object.getPrototypeOf(target)/__proto__setPrototypeOf(target, proto)— 拦截Object.setPrototypeOf(target, proto)
属性描述符
getOwnPropertyDescriptor(target, prop)— 拦截Object.getOwnPropertyDescriptor(target, prop)defineProperty(target, prop, descriptor)— 拦截Object.defineProperty(target, prop, descriptor)
扩展性
isExtensible(target)— 拦截Object.isExtensible(target)preventExtensions(target)— 拦截Object.preventExtensions(target)
键遍历
ownKeys(target)— 拦截以下所有操作:Object.getOwnPropertyNames()Object.getOwnPropertySymbols()Object.keys()Reflect.ownKeys()
其中最常用的是 get、set、has、deleteProperty、apply、construct 这 6 个。
