上一篇我们讲到vue2中使用Object.defineProperty()来进行数据劫持,因此暴露了几个问题.如对象属性的删除,新增.数组的下标和length操作. 在v3中不在考虑对低版本游览器的兼容,所以替换成成了Proxy来进行数据劫持.
reactive()
reactive是暴露给用户的api,他实现的函数是createReactiveObject(). 1判断传入的是否是Object,Array,Map,Set,WeakMap,WeakSet,如果不是直接返回 2.判断是否是响应式数据,如果是也直接返回 3.不是一个可观察的对象,直接返回(冻结属性) 4生成proxy实例,把它变成响应式
其他的v3和v2差距不大.
- 定义 track 用于保存这段函数代码。
- 定义 effect 用于执行代码。
- 定义 trigger 用于执行所有存储的代码。
get 读取属性
如果是数组且key是includes,indexof,lastindexof 会把目标对象转为 arrayInstrumentations 再执行(每个值手机依赖)
如果是普通对象(不是上面的1,2,3) createGetter() Reflect.get(target, key, receiver)中track收集依赖
将activeEffect作为依赖,然后收集到 target 相关的 depsMap 对应 key 下的依赖集合 dep 中。
Object.defineProperty 是在初始化阶段,即定义劫持对象的时候就已经递归执行了,而 Proxy 是在对象属性被访问的时候才递归执行下一步 reactive,这其实是一种延时定义子对象响应式的实现,在性能上会有较大的提升
set设置属性
通过 Reflect.set 求值,通过 trigger 函数派发通知(找到对于的depsMap,遍历 effects 执行相关的副作用函数)
其实 Vue.js 3.0 在响应式的实现思路和 Vue.js 2.x 差别并不大,主要就是 劫持数据的方式改成用 Proxy 实现,以及收集的依赖由 watcher 实例变成了组件副作用渲染函数 。