在 ECMAScript 2019 中使用 Proxy 对象定制对象的操作行为

· 约 7 分钟读完

什么是 Proxy 对象

在 ECMAScript6 中引入了 Proxy 对象,它本身是一种特殊的对象,用来定义在目标对象之前进行拦截、添加或修改操作的行为的代理。

Proxy 对象的基本用法

Proxy 对象最基本的使用方法是使用 Proxy 构造函数生成 Proxy 实例,然后用这个实例来代理相应的操作,示例代码如下:

在上面的代码中,我们新建了一个空对象 target,然后定义一个空对象 handler,最后使用 new Proxy() 方法将这两个对象进行关联,生成一个名为 proxy 的 Proxy 实例。

接着我们对这个 Proxy 实例进行一次属性赋值操作 proxy.foo = 'bar',由于我们并没有在 handler 对象中定义任何拦截行为,所以这个赋值操作实际上就是一次普通的属性赋值,将 'bar' 赋值给了 target 对象下的 foo 属性。接着我们使用 console.log() 打印了一下 target.foo,发现它的值就是当初我们赋予的 'bar'。

这样的一个 Proxy 对象虽然还无法发挥出太多作用,但是在理解了它的基础原理之后,我们就可以对它进行内容定制了。

Proxy 对象的使用场景

  1. 属性访问拦截器

使用 Proxy 对象我们可以拦截对象属性的读取、赋值以及删除操作,这为我们实现一些高效的目标提供了可能。下面是一个示例,当我们读取属性值时,返回的总是小写字符串。

在这段代码中,我们定义了一个对象 target,它包含一个属性 name 和值 'Foo'。接着我们定义了一个代理对象 handler,在这个对象中定义了一个 get 拦截器,我们在读取 proxy 中的属性时,它会拦截这个操作并对值进行转换处理。最终结果输出的字符串 'foo' 就是我们想要的结果。

  1. 函数调用拦截器

除了属性访问拦截器,我们还可以对函数调用进行拦截。比如下面这个示例,当我们调用 sum() 函数时,会拦截这个操作并对传入参数进行求和运算。

在这段代码中,我们参考了之前的定义形式,定义了一个函数 sum(),然后定义了一个代理对象 handler,它包含一个 apply 拦截器,在函数调用时对参数进行了求和运算。最后我们使用 proxy() 调用这个新函数,并传入三个参数 1、2、3,得到了我们预期的 6 的结果。

Proxy 对象的应用实战

  1. 防止对象上的属性被修改

使用 Proxy 对象可以避免对象上的属性被轻易地篡改,以及防止对象属性无意中被删除。为此,我们可以通过 Object.freeze() 方法来冻结对象的属性,依然需要修改时,实际上就会被拦截器 intercept 在内部。

在这段代码中,我们定义了一个空对象 obj,然后定义了一个代理对象 handler,包含了两个拦截器 set 和 deleteProperty,分别对属性设置和删除操作进行拦截。最后我们使用 Object.freeze() 方法将代理对象 proxy 进行冻结,从而避免对象上的属性被修改和删除。

  1. 构架中基于 Proxy 对象的实现

当代理对象中包含更为复杂的逻辑时,可以配合使用 Redux 等状态管理工具,来实现所需的逻辑控制。比如下面这个示例是一个构建过程中常用的 Prisma 实战,来处理后端数据的交互行为的,通过配合使用 Proxy 实现的。

在这段代码中,我们首先引入了一个第三方库 Prisma,它作为一个 ORM 框架,用来创建和管理数据库对象。接着我们定义了一个空代理对象 proxyHandler,用来定义 get 和 set 拦截器,这样我们就可以在读取和修改代理对象时进行必要的操作。

最后,我们使用 new Proxy() 方法生成了一个名为 Proxy 的代理实例,它包含两个异步函数 createUser() 和 getUsers(),分别用于创建用户和获取现有用户信息。其中,我们在创建用户数据时调用了 Prisma 的 user.create() 方法,通过 parseInt() 对 age 参数进行类型转换,确保参数类型正确。在获取用户数据时,我们使用 Prisma 的 user.findMany() 方法进行数据检索。

小结

在 ECMAScript 2019 中,我们可以使用 Proxy 对象对对象的访问、修改、删除等操作进行拦截和定制,实现更为复杂和灵活的应用场景。在实际应用中,经常可以在构建过程中适应现有框架和库工具,定制适合自己的个性化行为。这篇文章就是介绍这种代理对象的相关内容,希望对大家有所帮助。

来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/67d68f9ca941bf7134c5984c