Proxy代理深层属性

2,789 阅读2分钟

前言:ES6的Proxy默认是只会代理对象的浅层属性的(类似于Vue3的shallow API),那么如果想做到Vue3中代理深层属性该怎么办呢?这篇文章我们简单的介绍一下。

Proxy默认只代理一层对象的属性

例子一

Proxy的使用方法是new Proxy(obj,handler)不需要指定监听属性,这使得即便是后面加入对象的属性,也会监听getter和setter方法(Vue3的特点),如下所示。

image.png

image.png

例子2

注意点:如果是对对象的深层属性进行存取操作的话,他们都只会代理一层。从下面的例子可以看出,虽然我们是对p.friend.name进行操作,但是两次操作都被代理到了obj对象的getter方法。

因为他们只代理一层,实际上p.friend.name操作name属性,分为了两个步骤:p.friend和.name,也就是说,p.friend步骤是经过代理返回了一个非代理friend对象,然后再通过.name来设置对应的值。

也就是说,操作friend对象时,是直接操作原对象而非通过代理来操作该对象。

image.png

image.png

proxy代理深层属性

解决办法是,在Reflect返回的时候,判断是否是一个对象,如果是对象的话,再次用Proxy代理,返回代理对象

image.png

从下面的返回值可以看出,显示调用了p代理的get方法获取到friend对象的代理(输出1),然后在通过friend对象的代理修改name属性(输出2)。

image.png

Vue3源码

让我们看一下Vue3源码中是怎么代理响应式对象的吧

首先是reactive创建响应式对象API,内部其实就是通过Proxy创建并返回代理对象。

carbon (3).png

接下来是Proxyhandler中的get方法,内部其实就是判断target[key]的类型,如果是对象的话就重新调用reactive(其实就是用Proxy)代理并返回代理对象。

carbon (2).png