概念
给对象做代理,对target的操作进行拦截,比 Object.defineProperty (或Object.defineProperties )更更强大。既然Proxy可以对target的操作进行拦截,那至少会包含取值和赋值操作,下面来看看proxy是如何代理的。
const obj = new Proxy({}, {get(target, prop, receiver) {// receiver 指向的是调用这个函数的对象return 'dva';},set(target, prop, value, receiver) {}});obj.a // dva receiver指向objobj.b // dvalet child = {};Object.setPrototypeOf(child, obj);child.a // dva receiver指向child
上述代码通过new Proxy得到一个proxy实例,然后对其如何取值,得到的都是‘dva’。可以明显看出,这比Object.defineProperty强大的多,Object.defineProperty在对target属性进行拦截时,必须要指定键值来声明,而Proxy是只要是对其实例进行的操作,都会反映在实例的handler中。
Proxy构造函数接受两个参数,第一个是target,表示要被代理的对象。第二个是一个handler对象,其一些键值是对target的操作的拦截函数。返回一个Proxy实例。
Proxy可以拦截的操作
get(target, prop, receiver)拦截对target的取值操作。set(target, prop, value, reciver)拦截对target的赋值操作。apply(target, obj, args)拦截 Proxy 实例作为函数调用的操作,即proxy(...args),proxy.call(obj, ...args),proxy.apply(obj, args)等。construct(target,args)拦截 Proxy 实例作为构造函数调用的操作,比如new proxy(...args)。has(target, prop)拦截in操作符,返回一个Boolean值。deleteProperty(target, prop)拦截 delete 操作符,返回一个Boolean值。ownKeys(target)拦截Object.getOwnPropertyNames(proxy)、Object.getOwnPropertySymbols(proxy)、Object.keys(proxy)、for...in循环,返回一个数组。该方法返回目标对象所有自身的属性的属性名,而Object.keys()的返回结果仅包括目标对象自身的可遍历属性。getOwnPropertyDescriptor(target, prop)拦截Object.getOwnPropertyDescriptor(proxy, propKey),返回属性的描述对象。defineProperty(target, prop, desc)拦截Object.defineProperty(proxy, propKey, propDesc)、Object.defineProperties(proxy, propDescs),返回一个布尔值。preventExtensions(target)拦截Object.preventExtensions(proxy),返回一个布尔值。getPropertyOf(target)拦截Object.getPrototypeOf(proxy),返回一个对象。setPropertyOf(target)拦截Object.setPrototypeOf(proxy),返回一个布尔值。如果目标对象是函数,那么还有两种额外操作可以拦截。isExtensible(target)拦截Object.isExtensible(proxy),返回一个布尔值。 :::info 在handler中声明拦截函数,然后利用Proxy来实现所能想到的操作 :::Proxy实例方法
Proxy.revocable()创建一个可以被销毁的Proxy实例。返回的对象中包含一个proxy实例和revoke函数,revoke函数用来销毁Proxy实例。 ```javascript const { proxy, revoke} = Proxy.revocable({}, {});
revoke(); // 销毁proxy实例 proxy.a //// TypeError: Revoked
当执行`revoke`函数之后,再访问`Proxy`实例,就会抛出一个错误。<br />**使用场景:**1. 目标对象不允许直接访问,可以使用Proxy.revocable()做代理,访问结束后,销毁代理。<a name="CcVoX"></a>## this问题proxy对`target`不是透明代理,在不设置任何拦截时,通过proxy调用target中的方法,其中的this会指向proxy实例```javascriptconst target = {add() {console.log(this === proxy); // true}}const proxy = new Proxy(target, {});proxy.add()
如果想要this指向target,可以在对取值进行拦截,绑定this,然后调用。
可能的应用场景
- 在worker线程中,使用proxy异步访问DOM?
