Vue3.0Reactivity之readonly
前言
最后一个readonly
API了,这个API还是蛮容易理解的。
readonly
老规矩,找到它的定义
1 | export function readonly<T extends object>( |
这里和我们之前看reactive
的实现其实很像,都是主要由另一个函数createReactiveObject
来传入参数进行实现
1 | export function reactive(target: object) { |
那么我们只要关注参数即可。
这里传入了两个WeakMap,不过这两个WeakMap是建立只读代理到原生对象之间的关系。还传入了两个handlers,这里我们直接找到readonlyHandlers
。
1 | export const readonlyHandlers: ProxyHandler<object> = { |
这里我们可以对比reactive
使用到的mutableHandlers
1 | export const mutableHandlers: ProxyHandler<object> = { |
发现不同的地方在get
,set
和deleteProperty
参数上。
我们先看set
,deleteProperty
参数,它们直接就在这个对象里面实现。
对于只读的代理对象,当我们尝试对他设置值的时候,set
就会在开发环境下打印一个警告,删除属性的操作也是如此。
接下来我们看这个readonly
这个函数的实现
1 | // mutableHandlers用到的get |
发现其实和mutableHandlers
的实现都是通过createGetter
这个函数,只不过传入的参数不同而已。
找到这个createGetter
函数
1 | function createGetter(isReadonly = false, shallow = false) { |
这个函数传入两个参数
isReadOnly
是否只读shallow
是否为浅代理
所以其实我们可以发现有几种实现,比如reactive
,shallowReactive
,readonly
,shallowReadonly
,就是通过参数的真假组合出来的get所实现的。
这里我们不讲整个流程,我们发现当需要收集依赖,也就是执行track
函数的时候,都会先做一个判断,判断传进来的isReadonly
的真假。
也就是说,如果一个代理是只读的话,那么就没有必要对它执行依赖收集。因为它的set
和deleteProperty
没有触发它的依赖,不用触发,自然也就没必要收集。
至此,readonly
的实现基本上已经明朗,和reactive
的实现有相似之处,都返回了一个Proxy代理对象,不同的是对于get
,set
,deleteProperty
所使用的函数不相同。
通过拦截set
和deleteProperty
来使得赋值和删除属性无效,也避免了无意义的依赖收集。
后记
今天重新地同步了vue-next的仓库,发现已经出到beta.9
版本了,我也发现了一些代码做出了细微的改动,但是万变不离其宗,基本的原理还是一毛一样的。我看到的好像是增加了一些类型声明,还有一些函数的重构。
之后的话会写一些reactivity
实现上的一些细节的理解。如果看得懂virtual-dom的话,到时也会写写。