概念

给对象做代理,对target的操作进行拦截,比 Object.defineProperty (或Object.defineProperties )更更强大。既然Proxy可以对target的操作进行拦截,那至少会包含取值和赋值操作,下面来看看proxy是如何代理的。

  1. const obj = new Proxy({}, {
  2. get(target, prop, receiver) {
  3. // receiver 指向的是调用这个函数的对象
  4. return 'dva';
  5. },
  6. set(target, prop, value, receiver) {
  7. }
  8. });
  9. obj.a // dva receiver指向obj
  10. obj.b // dva
  11. let child = {};
  12. Object.setPrototypeOf(child, obj);
  13. 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

  1. 当执行`revoke`函数之后,再访问`Proxy`实例,就会抛出一个错误。<br />**使用场景:**
  2. 1. 目标对象不允许直接访问,可以使用Proxy.revocable()做代理,访问结束后,销毁代理。
  3. <a name="CcVoX"></a>
  4. ## this问题
  5. proxy`target`不是透明代理,在不设置任何拦截时,通过proxy调用target中的方法,其中的this会指向proxy实例
  6. ```javascript
  7. const target = {
  8. add() {
  9. console.log(this === proxy); // true
  10. }
  11. }
  12. const proxy = new Proxy(target, {});
  13. proxy.add()

如果想要this指向target,可以在对取值进行拦截,绑定this,然后调用。

可能的应用场景

  • 在worker线程中,使用proxy异步访问DOM?