前言
Proxy用于修改某些操作的默认行为。可以理解成在目标对象前设置一层拦截,外界对该对象的访问都必须通过这层拦截,提供一种机制可以对外界的访问进行过滤和改写。
var proxy = new Proxy(target, handler);
target表示所要拦截的目标,handler也是一个对象,用来定制拦截行为。例子如下:
var proxy = new Proxy({}, {
get(target, key, receiver){
console.log(`getting ${key}`);
return Reflect.get(target, key, receiver);
},
set(target, key, value, receiver){
console.log(`setting ${key}`);
return Reflect.set(target, key, value, receiver);
}
});
proxy.name = 'lili';
//setting name
对空对象进行拦截,重新定义了属性的读取和设置。
注意以下几点:
- 要使Proxy起作用,必须针对Proxy实例进行操作,而不是针对目标对象进行操作
- 如果handler没有设置任何拦截,那就等同于直接通向原对象
可以拦截的操作
| 方法名称 | 描述 | 例如 |
|---|---|---|
| get(target, propKey, receiver) | 拦截属性读取 | proxy.foo |
| set(target, propKey, value, receiver) | 拦截对象属性的设置 | proxy.foo = 'foo' |
| has(target, propKey) | 拦截propKey in proxy操作 | 'foo' in proxy |
| deleteProperty(target, propKey) | 拦截delete proxy[propKey] | |
| ownKeys(target) | 拦截Object.getOwnPropertyNames(proxy)、Object.getOwnPropertySymbols(proxy)、Object.keys(proxy) ,返回一个数组,包含目标对象所有自身属性的属性名 | |
| getOwnPropertyDescriptor(target, propKey) | 拦截Object.getOwnPropertyDescriptor(target, propKey), 返回属性的描述对象 | |
| defineProperty(target, propKey, propDesc) | 拦截Object.defineProperty(target, propKey, propDesc)、Object.defineProperties(target, propDescs) | |
| preventExtensions(target) | Object.~ | |
| getPrototypeOf(target) | Object.getPrototypeOf()、Reflect.getPrototypeOf() 、Object.prototype.proto、Object.prototype.isPrototypeOf()、instanceof | |
| isExtensible(target) | Object.~ | |
| setPrototypeOf(target, proto) | Object.~ | |
| apply(target, object, args) | 函数调用,直接、apply、call调用 | |
| contructor(target, args) | 作为构造函数调用的操作,new proxy(...args) |
如果一个属性不可配置(configurable)或不可写(writable),则改属性不能被代理。
如果属性不可配置或对象禁止扩展,has必须返回false
this 问题
虽然Proxy可以代理针对目标对象的访问,但它不是目标对象的透明代理,即不做任何拦截的情况下也无法保证与目标的行为一致。
const target = {
m(){
console.log(this === proxy);
}
}
const proxy = new Proxy(target, {});
target.m(); //false
proxy.m(); //true
应用
使用get拦截实现数组负数索引
function createArray(...elements){
return new Proxy([...elements], {
get(target, key, receiver){
let index = Number(key);
let maxIndex = target.length;
while (index < 0) {
index = maxIndex + index;
}
return Reflect.get(target, String(index), receiver);
}
})
}
var arr = createArray('a', 'b', 'c');
console.log(arr[-7]); //'c'