Proxy

一、语法

1
var p = new Proxy(target, handler);
传参说明
  • target:使用Proxy包装的目标对象,它可以是任何类型的对象,包括数组、函数或甚至另一个proxy对象
  • handler:一个对象,其属性是在对其执行操作时定义代理行为的函数
对象代理
1
2
3
4
5
6
7
8
9
10
var obj = new Proxy({}, {
get: function(target, key, receiver) {
console.log(`getting ${key}!`);
return Reflect.get(target, key, receiver);
},
set: function(target, key, value, receiver) {
console.log(`setting ${key}!`);
return Reflect.set(target, key, value, receiver);
}
});

注:

  • 要使得Proxy起作用,必须针对Proxy实例进行操作,而不是针对目标对象进行操作
  • 如果handler没有设置任何拦截,那就等同于直接通向原对象
  • Proxy 实例可以作为其他对象的原型对象
函数代理
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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

注:ProxyObject.defineProperty 的功能更强大。Vue的作者宣称将在Vue3.0版本后加入Proxy从而代替Object.defineProperty


二、创建可撤销的Proxy对象

1
2
3
4
// 创建
var revocable = Proxy.revocable(target, handler);
// 返回一个包含了所生成的代理对象本身以及该代理对象的撤销方法的对象
// 其结构为: {"proxy": proxy, "revoke": revoke}
返回对象参数说明
  • proxy:表示新生成的代理对象本身,和用一般方式 new Proxy(target, handler) 创建的代理对象没什么不同,只是它可以被撤销掉。
  • revoke:撤销方法,调用的时候不需要加任何参数,就可以撤销掉和它一起生成的那个代理对象。


注:一旦某个代理对象被撤销,它将变的几乎完全不可用,永远不可能恢复到原来的状态,在它身上执行任何的可代理操作都会抛出 TypeError 异常。同时和它关联的目标对象以及处理器对象将有可能被垃圾回收掉。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var revocable = Proxy.revocable({}, {
get(target, name) {
return "[[" + name + "]]";
}
});
var proxy = revocable.proxy;
proxy.foo; // "[[foo]]"

revocable.revoke(); // 执行撤销方法

proxy.foo; // TypeError
proxy.foo = 1 // 同样 TypeError
delete proxy.foo; // 还是 TypeError
typeof proxy // "object",因为 typeof 不属于可代理操作


三、13 种Proxy代理操作

  • get(target, propKey, receiver):拦截对象属性的读取,比如proxy.fooproxy['foo']
  • set(target, propKey, value, receiver):拦截对象属性的设置,比如proxy.foo = vproxy['foo'] = v,返回一个布尔值
  • has(target, propKey):拦截propKey in proxy的操作,返回一个布尔值
  • deleteProperty(target, propKey):拦截delete proxy[propKey]的操作,返回一个布尔值
  • 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)