Proxy 让我们能够对任何对象的绝大部分行动举行监听和过问,完成更多的自定义顺序行动。
用法:new Proxy(target, handler)。
Proxy 经由历程设置行动监听要领来捕捉顺序对对应对象的行动。
const obj = {};
const proxy = new Proxy(obj, {
// ...
})
Proxy 的组织器接收两个参数,第一个参数为须要举行包装的目的对象,第二个参数则为用于监听目的对象行动的监听器,个中监听器能够接收一些参数以监听相对应的顺序行动。
监听属性、参数及监听内容
属性值 | 监听器参数 | 监听内容 |
---|---|---|
has | (target, prop) | 监听 in 语句的运用 |
get | (target, prop, reciver) | 监听目的对象的属性读取 |
set | (target, prop, value, reciver) | 监听目的对象的属性赋值 |
deleteProperty | (target, prop) | 监听 delete 语句对目的对象的删除属性行动 |
ownKeys | (target) | 监听 Object.getOwnPropertyName() 的读取 |
apply | (target, thisArg, arguments) | 监听目的函数(作为目的对象)的挪用行动 |
construct | (target, arguments, newTarget) | 监听目的组织函数(作为目的对象)应用 new 而天生实例的行动 |
getPrototypeOf | (target) | 监听 Objext.getPrototypeOf() 的读取 |
setPrototypeOf | (target, prototype) | 监听 Objext.setPrototypeOf() 的挪用 |
isExtensible | (target) | 监听 Objext.isExtensible() 的读取 |
preventExtensions | (target) | 监听 Objext.preventExtensions() 的读取 |
getOwnPropertyDescriptor | (target, prop) | 监听 Objext.getOwnPropertyDescriptor() 的挪用 |
defineProperty | (target, property, descriptor) | 监听 Object.defineProperty() 的挪用 |
has
能够经由历程为 Proxy 的 handler 定义 has 监听要领,来监听顺序经由历程 in 语句来搜检一个字符串或数字是不是为该 Proxy 的目的对象中某个属性的属性键的历程。
const p = new Proxy({}, {
has(target, prop){
console.log(`Checking "${prop}" is in the target or not`);
return true;
}
})
console.log('foo' in p);
// Checking "foo" is in the target or not
// true
该监听要领有两个须要注重的处所,假如碰到这两种状况,便会抛出 TypeError 毛病。
1.当目的对象被其他顺序经由历程 Object.preventExtensions() 禁用了属性拓展 (该对象没法再增添新的属性,只能对当前已有的属性举行操纵,包含读取、操纵和删除,然则一旦删除就没法再定义) 功用,且被搜检的属性键确切存在与目的对象中,该监听要领便不能返回 false。
const obj = {foo: 1};
Object.preventExtensions(obj);
const p = new Proxy(obj, {
has(target, prop){
console.log(`Checking "${prop}" is in the target or not`);
return false;
}
})
console.log('foo' in p);
//抛出Uncaught TypeError:
2.当被搜检的属性键存在与目的对象中,且该属性的 configurable 设置是 false 时,该监听要领不能返回 false。
const obj = {};
Object.defineProperty(obj, 'foo', {
configurable: false,
value: 10
})
const p = new Proxy(obj, {
has(target, prop){
console.log(`Checking "${prop}" is in the target or not`);
return false;
}
})
console.log('foo' in p);
//抛出Uncaught TypeError:
get
Getter只能对已知的属性键举行监听,而没法对一切属性读取行动举行阻拦,而 Proxy 能够经由历程设定 get 监听要领,阻拦和过问目的对象的一切属性读取行动。
const obj = {foo: 1};
const p = new Proxy(obj, {
get(target, prop){
console.log(`Program is trying to fetch the property "${prop}".`);
return target[prop];
}
})
alert(p.foo); // Program is trying to fetch the property "foo".
alert(p.something); // Program is trying to fetch the property "something".
这个监听要领也存在须要注重的处所——当目的对象被读取属性的 configurable 和 writable 属性都为 false 时,监听要领末了返回的值必需与目的对象的原属性值一致。
const obj = {};
Object.defineProperty(obj, 'foo', {
configurable: false,
value: 10,
writable: false
})
const p = new Proxy(obj, {
get(target, prop){
return 20;
}
})
console.log(p.foo);
set
handler.set 用于监听目的对象的一切属性赋值行动。注重,假如目的对象本身的某个属性是不可写也不可设置的,那末 set 不得转变这个属性的值,只能返回一样的值,不然报错。
const obj = {};
const p = new Proxy(obj, {
set(target, prop, value){
console.log(`Setting value "${value}" on the key "${prop}" in the target object`);
target[prop] = value;
return true;
}
})
p.foo = 1;
// Setting value "1" on the key "foo" in the target object
apply
handler.apply , Proxy 也为作为目的对象的函数供应了监听其挪用行动的属性。
const sum = function(...args) {
return args
.map(Number)
.filter(Boolean)
.reduce((a, b) => a + b);
}
const p = new Proxy(sum, {
apply(target, thisArg, args) {
console.log(`Function is being called with arguments [${args.join()}] and context ${thisArg}`);
return target.call(thisArg, ...args);
}
})
console.log(p(1, 2, 3));
// Function is being called with arguments [1,2,3] and context undefined
// 6
construct
handler.construct, Proxy 也能够将类作为目的监听对象,并监听其经由历程 new 语句来临盆新实例的行动,这一样能够运用再作为组织器的组织函数上。
class Foo{};
const p = new Proxy(Foo, {
construct(target, args, newTarget){
return {arguments: args} // 这里返回的效果会是 new 所获得的实例
}
});
const obj = new p(1, 2, 3);
console.log(obj.arguments); // [1, 2, 3]
建立可消除 Proxy 对象
用法:Proxy.revocable(target, handler) : (proxy, revoke)。
const obj = {foo: 10};
const revocable = Proxy.revocable(obj, {
get(target, prop){
return 20;
}
})
const proxy = revocable.proxy;
console.log(proxy.foo); // 20
revocable.revoke();
console.log(proxy.foo);
// TypeError: Cannot perform 'get' on a proxy that has been revoked
Proxy.revocable(target, handler) 会返回一个带有两个属性的对象,个中一个 proxy 就是该函数所天生的可消除 Proxy 对象,而另一个 revoke 则是将适才的 Proxy 对象消除的消除要领。