首先我们要知道响应式的基本流程
- 侦测数据的变化
- 收集视图依赖了哪些数据数据变化时,
- 自动“通知”需要更新的视图部分,并进行更新 对应专业俗语分别是:
- 数据劫持 / 数据代理
- 依赖收集
- 发布订阅模式
响应式的依赖
- vue2中使用js中的Object.defineProperty来实现
- vue3中使用ES6中的 Proxy来实现
Object.defineProperty
Vue通过设定对象属性的 setter/getter 方法来监听数据的变化,通过getter进行依赖收集,而每个setter方法就是一个观察者,在数据变更的时候通知订阅者更新视图。
Vue 通过 Object.defineProperty来将对象的key转换成 getter/setter的形式来追踪变化,但 getter/setter只能追踪一个数据是否被修改,无法追踪新增属性和删除属性。
但是:
- 删除属性,我们可以用 vm.$delete实现
- 添加响应式属性可以使用 Vue.set(location,a,1) 方法向嵌套对象添加响应式属性
- 添加响应式属性也可以给这个对象重新赋值,比如
data.location={...data.location,a:1}
Proxy
Proxy 是 JavaScript 2015 的一个新特性。 Proxy 的代理是针对整个对象的,而不是对象的某个属性,因此不同于 Object.defineProperty 的必须遍历对象每个属性, Proxy 只需要做一层代理就可以监听同级结构下的所有属性变化,当然对于深层结构,递归还是需要进行的。此外 Proxy支持代理数组的变化。他有个缺点就是兼容性不是太好。
订阅者 Dep和观察者Watcher
- Dep 类,用于解耦属性的依赖收集和派发更新操作,说得具体点,它的主要作用是用来存放 Watcher 观察者对象。我们可以把Watcher理解成一个中介的角色,数据发生变化时通知它,然后它再通知其他地方。
- 当外界通过Watcher读取数据时,便会触发getter从而将Watcher添加到依赖中,哪个Watcher触发了getter,就把哪个Watcher收集到Dep中。当数据发生变化时,会循环依赖列表,把所有的Watcher都通知一遍。(在getter中收集依赖,在setter中触发依赖。)
常规理解:
-
组件加载时,先会使Object.defineProperty对于data里面的数据进行数据劫持 / 数据代理,也就是为每个属性绑定getter和seter.引入dep通过key和watcher对象进行绑定,
-
在数据改变时watcher在getter中收集依赖,把收集到的当前watcher存储在dep中(在这里会进行key的对比,如果有这个key对应的watcher,那不会添加新的watcher,反过来没有就会添加新的watcher),然后循环依赖列表,通知watcher,(在setter中触发更新依赖)
个人理解希望对大家有点用哈
希望大家一起早早下班,快乐摸鱼,哈哈哈哈。