响应式原理

140 阅读3分钟

数据双向绑定原理?

Vue双向数据绑定过程中,这边数据改变了怎么通知另一边改变?

Vue数据响应式就是:数据变化更新视图视图变化更新数据

Vue数据响应式是通过数据劫持+发布订阅模式来实现的。通过数据劫持侦测数据变化;通过发布订阅模式进行依赖收集与视图更新。

Vue2的数据劫持就是利用了js原生提供的Object.defineProperty()方法。通过这个方法来劫持data对象中各个属性的gettersetter,在数据变动时就通知订阅者Watcher,订阅者就会触发它的update方法,对视图进行更新。

vue2的数据响应式缺点:①监听不到数组值的变化;②监听不到对象属性的新增或删除。

解决方案:使用Vue.set (vm.$set)Vue.delete (vm.$delete)这些API

解除响应式:对数据进行深拷贝,或者使用Object.freeze()这个API对数据进行冻结。

在Vue2底层中它具体是通过实现Observe、Dep、Watcher、Compile这四个类来完成双向绑定原理的:

  1. Observe:用于进行数据劫持,就是把data对象的每个属性通过Object.defineProperty()转换为带有getter和setter的属性。实现对data数据的劫持监听。
  2. Dep:负责依赖收集和发布通知。里面通过数组储存所有Watcher,当Observe侦测到数据变动就立即调用Dep.notify(),遍历数组中的Watcher,并调用Watcher中的update方法。
  3. Watcher:主要用于触发执行更新渲染。Dep中收集依赖,就是收集Watcher。当Watcher中的update方法被调用时就会触发Compile中的patch()给真实Dom打补丁,更新相应视图。
  4. Compile:主要工作是解析模板指令,将模板中的指令替换成数据。对每个节点元素进行扫描和解析,将相关指令对应初始化成一个订阅者Watcher,一旦数据有变动,收到通知,更新视图。

vue响应式原理图.png

数据劫持:Object.defineProperty()

发布订阅模式:

  • 订阅者Watch --- 【负责订阅一些事件】

    • update():当事件发生时具体要做的事情
  • 发布者Dep --- 【负责依赖收集和发布通知】

    • subs数组:存储所有的订阅者Watch实例
    • addSub():添加观察者到subs数组中
    • notify():发布订阅的方法,当事件发生就调用所有观察者的update()方法

订阅者就是Dom元素

VUE2:Object.defineProperty()

VUE3:Proxy proxy代理是es6推出的新api,可以弥补vue2数据响应式的缺点,所以vue3用proxy替换了Object.defineProperty()

视图变化更新数据(事件监听),数据变化更新视图(数据劫持 + 发布订阅模式)

其实只有对象和数组才会有这种删除和增加的操作,而其他的字符串等都是直接赋值修改的,getter/setter都是能检测到的,所以observe对象和数组的时候会创建一个dep,用来收集订阅和发布更新