1. Proxy是什么?
Proxy用于修改某些基本操作的默认行为(或者说自定义行为),等同于在语言层面做出修改,所以属于一种"元编程",即对编程语言进行编程。
Proxy是代理的意思,可以理解成,在目标对象之前设了一层"拦截",可以对外界的访问进行过滤和改写,代理器由此而来。
var proxy = new Proxy(target, handler);
-- new Proxy() : 生成一个Proxy实例;
-- target: 所要拦截的目标对象;
-- handler: 一个对象,定制拦截行为。
如果没有设置handler拦截规则,换言之,是一个空对象的话,那么proxy就直接通向原对象。
Proxy支持的拦截操作13种:
- get(target, propKey, receiver) : 拦截对象的读取,比如proxy.foo proxy['foo']
- set(target, propKey, value, receiver): 拦截对象属性的设置,比如proxy.foo = v或proxy['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) ,返回布尔值。
- isExtensible(target): 拦截Object.isExtensible(proxy), 返回一个布尔值。
- getPrototypeOf(target): 拦截Object. getPrototypeOf(proxy), 返回一个对象。
- setPrototypeOf(target): 拦截Object. setPrototypeOf(proxy, proto), 返回一个布尔值.。如果目标对象是函数,那么还有以下两种操作可以拦截.
- apply(target, object, args): 拦截Proxy实例作为函数调用的操作,比如:
proxy(...args)、 proxy.call(object, ...args)、 proxy.apply(...)
- construct(target, args): 拦截Proxy实例作为构造函数调用的操作,比如 new proxy(...args).
2. Proxy.revocable()
Proxy.revocable返回一个可取消的Proxy实例, 这个实例对象有proxy属性和revoke属性。
Proxy.revocableProxy.revocable 的一个使用场景:目标对象不允许直接访问,必须代理访问,一旦访问结束,就收回代理权,不允许再次访问。
3. this问题
虽然proxy可以代理对象目标对象的访问,但它不是目标对象的透明代理,即不做任何拦截的情况下,也无法保证与目标对象的行为一致。主要原因是Proxy代理的情况下,目标对象内部的this关键字会指向Proxy代理。
此外,有些原生对象的属性,只有通过正确的this才能访问到,所以Proxy也无法代理这些原生对象的属性。
上面代码中,getDate方法只能在Date对象实例上使用,如果this不是Date对象实例就会报错。这时,this绑定原始对象,就可以解决这个问题。
Proxy可以应用在很多地方,想着用,要多用才能更会用。我也才是刚入门而已呀 ~~~
网友评论