概念
Proxy 用于修改某些操作的默认行为,等同于在语言层面做出修改,所以属于一种 " 元编程 "(meta programming),即对编程语言进行编程
Proxy 实际上重载(overload)了点运算符,即用自己的定义覆盖了语言的原始定义
注意,要使得 Proxy 起作用,必须针对 Proxy 实例(上例是 proxy 对象)进行操作,而不是针对目标对象(上例是空对象)进行操作
示例
如果 handler 没有设置任何拦截,那就等同于直接通向原对象。
同一个拦截器函数,可以设置拦截多个操作。
var handler = {
get: function(target, name) {
if (name === 'prototype') {
return Object.prototype;
}
return 'Hello, ' + name;
},
apply: function(target, thisBinding, args) {
return args[0];
},
construct: function(target, args) {
return {value: args[1]};
}
};
var fproxy = new Proxy(function(x, y) {
return x + y;
}, handler);
fproxy(1, 2) // 1
new fproxy(1, 2) // {value: 2}
fproxy.prototype === Object.prototype // true
fproxy.foo === "Hello, foo" // true对于可以设置、但没有设置拦截的操作,则直接落在目标对象上,按照原先的方式产生结果。
如果一个属性不可配置(configurable)且不可写(writable),则 Proxy 不能修改该属性,否则通过 Proxy 对象访问该属性会报错
拦截操作

apply()
apply 方法拦截函数的调用、 call 和 apply 操作。 apply 方法可以接受三个参数,分别是目标对象、目标对象的上下文对象( this )和目标对象的参数数组
has()
has() 拦截只对 in 运算符生效,对 for...in 循环不生效,导致不符合要求的属性没有被 for...in 循环所排除
receiver 含义
Proxy 或者继承于 Proxy 的对象
let user = {
_name: "张三",
get name() {
return this._name;
}
};
let userProxy = new Proxy(user, {
get(target, prop, receiver) {
return Reflect.get(target, prop);
// return Reflect.get(target, prop, receiver); // 李四
// return target[prop]; // (*) target = user
}
});
let admin = {
__proto__: userProxy,
_name: "李四"
};
// 期待 『李四』,却输出了 『张三』(?!?)
console.log(admin.name); // => 张三Proxy.revocable()
Proxy.revocable() 方法返回一个可取消的 Proxy 实例。
let target = {};
let handler = {};
let {proxy, revoke} = Proxy.revocable(target, handler);
proxy.foo = 123;
proxy.foo // 123
revoke();
proxy.foo // TypeError: RevokedProxy.revocable() 方法返回一个对象,该对象的 proxy 属性是 Proxy 实例,revoke 属性是一个函数,可以取消 Proxy 实例。上面代码中,当执行 revoke 函数之后,再访问 Proxy 实例,就会抛出一个错误。
Proxy.revocable() 的一个使用场景是,目标对象不允许直接访问,必须通过代理访问,一旦访问结束,就收回代理权,不允许再次访问
this 指向
虽然 Proxy 可以代理针对目标对象的访问,但它不是目标对象的透明代理,即不做任何拦截的情况下,也无法保证与目标对象的行为一致。主要原因就是在 Proxy 代理的情况下,目标对象内部的 this 关键字会指向 Proxy 代理。
const target = {
m: function () {
console.log(this === proxy);
}
};
const handler = {};
const proxy = new Proxy(target, handler);
target.m() // false
proxy.m() // true上面代码中,一旦 proxy 代理 target,target.m() 内部的 this 就是指向 proxy,而不是 target。所以,虽然 proxy 没有做任何拦截,target.m() 和 proxy.m() 返回不一样的结果。