浅谈Vue3响应式原理

263 阅读2分钟

首先在开始之前,我们需要知道ES6新增的Proxy,Reflect、WeakMap、Map等知识。Proxy是Vue3响应式原理的核心,他不同于Object.defineProperty(vue2响应式原理的核心),Proxy是一个类,Proxy可以代理整个对象,并且内置有9种捕获器,常见的捕获器主要有get、set、has、deleteProperty等。

code.png

一、响应式数据与副作用函数

如图所示,一个info对象,一个info的副作用函数,响应式原理的本质就是当info发生了变化,对应通知它的副作用函数的调用,因此我们可以借助Proxy拦截对象的get和set操作,在get前收集依赖、在set操作后调用它的副作用函数。

收集依赖

首先创建一个Depend的类,用于收集和派发副作用函数。接下来需要定义一个watch函数,也是用于收集副作用函数,原因是当我们的副作用函数不叫effect、而是一个匿名函数的情况下也能够正常的收集依赖。

code1.png

监听变化

在收集好依赖后,只需要监听get操作收集依赖,set操作执行副作用函数。这里解释一下Reflect,它和Object的区别不是很大,主要是因为JS的设计之初有许多的方法不知道往哪里放,就全都塞进了Object,有兴趣的小伙伴可以对比一下Object和Reflect的区别,这里可以看到控制台打印了"info的数据发生了变化"。

code3.png

依赖管理的缺陷

当我们只是改变了info中的name属性后,但是age的副作用函数却也被调用了,这显而易见是不正确的操作,因此我们要管理好每个属性对应的依赖,假设我们有一个大桶bucket,里面有许多的key对应的各自的map,而map里面也存放着对应的依赖。

code4.png

正确的收集依赖

创建一个getDepend的函数,就好比有一个桶,里面装着各种proxy对象,每个对象单独的key保存着自己的副作用函数。weakMap是弱引用,他不会影响垃圾回收器的工作,一旦表达式执行完毕,对象中的key也会被从内存中移除。

code5.png 而我们的proxy对象也应该换成这样子收集依赖、派发依赖。

code7.png 优化一下Depend类中的Depend中的方法,因为普通的数组无法去掉重复的调用,因此reactive应该换成ES6新增的set方法。

code8.png 最后完成对reactive的封装,vue3响应式原理简单的被实现了。

code99.png 第一次写掘金帖子也是为了锻炼自己,若有错误的地方欢迎指正。