Vue3它来了它来了,它带着Proxy走来了

11686 17 1 技术 2023-03-01

teais-f0mok

Vue3改用Proxy

最近的一次分享会议上,组内的某个小伙伴分享了关于Vue3的一些东西,因为我部门负责核心业务事务繁多,所以一直没有关心Vue3的发展。只听说Vue3 的升级点不少,优化虚拟DOM之后响应更快了,原来的API方式从选项式改成了组合式,更重要的是TypeScript编写提供了类型检查和代码提示的支持等。

响应底层也是从 defineProperty 换成了 Proxy ,之前写过前者原理 双向绑定所使用到的defineProperty(),于是就好奇想知道后者 Proxy 是怎么实现响应的。

我们知道Vue2是处于IE时代,还需要兼容IE9,所以用的是defineProperty去做响应式底层。但是微软系统推送的更新计划文档中明确表示,微软将于2023年2月14日关闭IE浏览器,取而代之的是Edge浏览器。IE的退出,ES6的完整支持使得Vue3发版大刀阔斧推进。ES6中有一个新特性 Proxy

Proxy可以一次代理整个对象,defineProperty只代理对象上的某个属性;Proxy对代理对象的监听更加丰富;Proxy代理对象会生成新的对象,不会修改被代理对象本身。

Object.defineProperty(obj, prop, descriptor) 传入一个对象,第二个参数传入该对象属性,一次只能劫持对象中一个属性,基本类型是OK,但是遇到引用类型(对象,数组)的数据,就要通过递归+遍历才能监控到,内部嵌套越深递归遍历越多。而 Proxy 则不同,可以直接劫持整个对象,写Vue2的时候我们很经常会出现一个问题,数组的更改要专门的数组变异方法来确保这些操作能够被追踪到。

两种声明方法

Vue3提供了ref和reactive两个方法去声明响应式数据,不再像Vue2写在data里面就自动转换成响应式了,看看官网的解释👇

微信截图_20241121011435

再看看声明这两个响应式之后打印出来什么东西

微信截图_20241121014313

reactive

reactive比较好理解,该方法传入一个引用类型数据(对象或数组),会返回一个Proxy对象 ②,查看通过源码发现调用了Proxy方法,劫持了整个对象的变化; 微信截图_20241121013514

假设传入非引用类型则抛出一个错误【类型“number”的参数不能赋给类型“object”的参数】,并返回本身 ①,这时候则不具备响应式。如果将reactive声明的对象重新赋值 obj = { a: 1 } 则会覆盖Proxy并丢失响应式。

微信图片_20241121012542

ref

ref是官方无脑推荐使用的,声明后返回一个RefImpl对象,通过查看源码发现,底层原理还是Proxy。

微信截图_20241121021057

类的构造器会进行一层判断,是否是引用类型数据,如果是则调用上面reactive实现数据劫持,如果不是则使用普通对象的 gettersetter 实现数据劫持;所以ref对于引用类型数据还是会调用reactive方法,访问这两种类型数据则都是通过 .value。为了代码统一,也就是官方建议使用ref声明的原因。

© 2020 peal.cc 粤ICP备2020133024号