zl程序教程

您现在的位置是:首页 >  IT要闻

当前栏目

Vue面试必须会的Proxy

2023-02-18 16:43:13 时间

什么是Proxy

Proxy是ECMAScript新增的api。可以为开发者提供拦截并向基本操作嵌入额外的行为的能力。

Proxy可以给目标定义一个相关联的代理对象,而这个代理对象可以作为抽象的目标对象来使用。在对目标对象的各种操作影响目标对象之前,可以在代理对象中对这些操作加以控制。

大部分现代浏览器均已支持,支持用户的比例已经非常接近Object: defineProperty

96.31% Proxy 97.33% Object: defineProperty

定义捕获器

我认为Proxy的精髓就是捕获器。

使用代理的主要目的是可以定义捕获器(trap)捕获器就是在处理程序对象中定义的“基本操作的拦截器”。每个处理程程序对象可以包含零个或多个捕获器,每个捕获器都对应一种基本操作,可以直接或间接在代理对象上调用。每次在代理对象上调用这些基本操作时,代理可以在这些操作传播到目标对象之前先调用捕获器函数,从而拦截并修改相应的行为。

捕获器(trap)是从操作系统中借用的概念。在操作系统中,捕获器是程序流中的一个同步中断,可以暂停程序流,转而执行一段子例程,之后再返回原始程序流。

以最常用的set为例:

捕获set()基本操作

set()捕获器会在设置属性值的操作中被调用。对应的反射API方法为Reflect.set()。

const myTarget ={}
const proxy = new Proxy (myTarget,{
    set(target,property,value,receiver){
      console.log ('set ()')
      return Reflect.set (..arguments)
    }
});

proxy.foo ='bar';

1.返回值

返回true表示成功;返回false表示失败,严格模式下会抛出TypeError。

2.拦截的操作

  • proxy.property = value
  • Object.create(proxy)[property] = value
  • proxy [property]=value
  • Reflect.set(proxy,property,value,receiver)

3.捕获器处理程序参数

  • property:引用的目标对象上的字符串键属性。
  • target:目标对象。
  • value:要赋给属性的值。
  • receiver:接收最初赋值的对象。

如果target.property不可写且不可配置,则不能修改目标属性的值。

4.捕获器不变式

如果target.property不可写且不可配置,则不可修改目标属性的值。

如果target.property不可配置且[[set]]特性为undefined,则不能修改目标属性的值。

在严格模式下,处理程序中返回false会抛出TypeError。

捕获其他基本操作

代理的捕获器可以捕获13种不同的基本操作。这些操作有各自不同的反射API方法、参数、关联ECMAScript操作和不变式。

下面列出几个可捕获的,常用的基本操作。

捕获get()基本操作

get()捕获器会在获取属性值的操作中被调用。对应的反射AP方法为Ref1ect.get()。

const myTarget ={} 
const proxy = new Proxy (myTarget,{ 
  get(target,property,receiver){       
    console.log ('get ()')
    return Reflect.get(..arguments)
  }
});
proxy.foo;

1.返回值

返回值无限制。

2.拦截的操作

  • proxy.property
  • Object.create(proxy)[property]
  • proxy [property]
  • Reflect.get(proxy,property,,receiver)

3.捕获器处理程序参数

  • property:引用的目标对象上的字符串键属性。
  • target:目标对象。
  • receiver:代理对象或继承代理对象的对象。

如果target.property不可写且不可配置,则不能修改目标属性的值。

4.捕获器不变式

如果target.property不可写且不可配置,则处理程序返回的值必须与target.property匹配。

如果target.property不可配置且[[Get]]特性为undefined,处理程序的返回值也必须是undefined。

捕获has()基本操作

const myTarget ={}
const proxy = new Proxy (myTarget,{
  has(target,property){
    console.log ('has ()')
    return Reflect.has(..arguments)
  }
});
'foo'in proxy;

1.返回值

has()必须返回布尔值,表示属性是否存在。返回非布尔值会被转型为布尔值。

2.拦截的操作

  • property in proxy
  • property in Object.create(proxy)
  • with(proxy){(property);}
  • Reflect.has(proxy,property)

3.捕获器处理程序参数

  • target:目标对象。
  • property:引用的目标对象上的字符串键属性。

4.捕获器不变式

如果target.property存在且不可配置,则处理程序必须返回true。

如果target.property存在且目标对象不可扩展,则处理程序必须返回true。

捕获apply()基本操作

apply()捕获器会在调用函数时中被调用。对应的反射AP方法为Retlect,apply()。

const myTarget =() => {}
const proxy = new Proxy (myTarget,{
  apply(target,thisArg,...argumentsList){
    console.log ('apply()')
    return Reflect.apply(...arguments)
  }
});
proxy();

捕获construct()基本操作

construct()捕获器会在new操作符中被调用。对应的反射API方法为Reflect.construct()。

const myTarget =() => {}
const proxy = new Proxy (myTarget,{
  apply(target,argumentsList,newTarget){
    console.log ('construct()')
    return Reflect.construct(...arguments) 
  }
});
new proxy();

1.返回值

construct()必须返回一个对象。

2.拦截的操作

  • new proxy(...argumentsList)
  • Reflect.construct(target,argumentsList,newTarget)

3.捕获器处理程序参数

  • target:目标构造函数。
  • argumentsList:传给目标构造函数的参数列表。
  • newTarget:最初被调用的构造函数。

4.捕获器不变式

target必须可以用作构造函数。


参考: 《JavaScript高级程序设计》 https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Proxy