响应式原理

113 阅读3分钟

首先我们要知道响应式的基本流程

  1. 侦测数据的变化
  2. 收集视图依赖了哪些数据数据变化时,
  3. 自动“通知”需要更新的视图部分,并进行更新 对应专业俗语分别是:
  4. 数据劫持 / 数据代理
  5. 依赖收集
  6. 发布订阅模式

响应式的依赖

  1. vue2中使用js中的Object.defineProperty来实现
  2. vue3中使用ES6中的 Proxy来实现

Object.defineProperty

Vue通过设定对象属性的 setter/getter 方法来监听数据的变化,通过getter进行依赖收集,而每个setter方法就是一个观察者,在数据变更的时候通知订阅者更新视图。

Vue 通过 Object.defineProperty来将对象的key转换成 getter/setter的形式来追踪变化,但 getter/setter只能追踪一个数据是否被修改,无法追踪新增属性和删除属性。

但是:

  1. 删除属性,我们可以用 vm.$delete实现
  2. 添加响应式属性可以使用 Vue.set(location,a,1) 方法向嵌套对象添加响应式属性
  3. 添加响应式属性也可以给这个对象重新赋值,比如 data.location={...data.location,a:1}

Proxy

Proxy 是 JavaScript 2015 的一个新特性。 Proxy 的代理是针对整个对象的,而不是对象的某个属性,因此不同于 Object.defineProperty 的必须遍历对象每个属性, Proxy 只需要做一层代理就可以监听同级结构下的所有属性变化,当然对于深层结构,递归还是需要进行的。此外 Proxy支持代理数组的变化。他有个缺点就是兼容性不是太好。

订阅者 Dep和观察者Watcher

  1. Dep 类,用于解耦属性的依赖收集和派发更新操作,说得具体点,它的主要作用是用来存放 Watcher 观察者对象。我们可以把Watcher理解成一个中介的角色,数据发生变化时通知它,然后它再通知其他地方。
  2. 当外界通过Watcher读取数据时,便会触发getter从而将Watcher添加到依赖中,哪个Watcher触发了getter,就把哪个Watcher收集到Dep中。当数据发生变化时,会循环依赖列表,把所有的Watcher都通知一遍。(在getter中收集依赖,在setter中触发依赖。)

常规理解:

  1. 组件加载时,先会使Object.defineProperty对于data里面的数据进行数据劫持 / 数据代理,也就是为每个属性绑定getter和seter.引入dep通过key和watcher对象进行绑定,

  2. 在数据改变时watcher在getter中收集依赖,把收集到的当前watcher存储在dep中(在这里会进行key的对比,如果有这个key对应的watcher,那不会添加新的watcher,反过来没有就会添加新的watcher),然后循环依赖列表,通知watcher,(在setter中触发更新依赖)

示意图.png

  个人理解希望对大家有点用哈
  希望大家一起早早下班,快乐摸鱼,哈哈哈哈。