我的回答

  1. data中的数据使用Object.definPropertype进行劫持, 并且使用Dep.target获得watch, 如果遇到数组需要将数组的7个原型方法进行重写, 深层的字段要进行递归劫持
  2. 将watcher放到对应的dep中, 如果属性发生变化触发dep.notify(), 然后调用watcher的update方法

    参考回答

    Vue依赖收集

    在初始化vue每个组件时,会对组件的data进行初始化,就会将由普通对象变成响应式对象,在这个过程中便会进行依赖收集的相关逻辑

    1. function defieneReactive(obj,key,val){
    2. const dep=new Dep();
    3. //...
    4. Object.defineProperty(obj,key,{
    5. //...
    6. get:function reactiveGetter(){
    7. if(Dep.target){
    8. dep.depend();
    9. //...
    10. }
    11. return val
    12. }
    13. })
    14. }

    上面的代码主要说明:const dep=new Dep() 实例化一个Dep实例,然后能在get函数中通过dep.depend() 进行依赖收集

    Dep

    Dep是整个依赖收集的核心

    1. class Dep {
    2. static target;
    3. subs;
    4. constructor () {
    5. ...
    6. this.subs = [];
    7. }
    8. addSub (sub) { //添加
    9. this.subs.push(sub)
    10. }
    11. removeSub (sub) { //移除
    12. remove(this.sub, sub)
    13. }
    14. depend () { //target添加
    15. if(Dep.target){
    16. Dep.target.addDep(this)
    17. }
    18. }
    19. notify () { //响应
    20. const subs = this.subds.slice();
    21. for(let i = 0;i < subs.length; i++){
    22. subs[i].update()
    23. }
    24. }
    25. }

    Dep是一个class,里面有一个静态属性static,指向全局唯一的Watcher,保证了同一时间全局只有一个watcher被计算,另一个属性subs则是一个watcher数组,所以dep实际上就是对watcher的管理

    watcher

    1. class Watcher {
    2. getter;
    3. ...
    4. constructor (vm, expression){
    5. ...
    6. this.getter = expression;
    7. this.get();
    8. }
    9. get () {
    10. pushTarget(this);
    11. value = this.getter.call(vm, vm)
    12. ...
    13. return value
    14. }
    15. addDep (dep){
    16. ...
    17. dep.addSub(this)
    18. }
    19. ...
    20. }
    21. function pushTarget (_target) {
    22. Dep.target = _target
    23. }

    watcher是一个class,定义了一些方法,其中和依赖收集相关的函数是get、addDep

    过程

    在实例化Vue时,依赖收集的相关过程: 初始化状态 initState,这中间便会通过defineReactive将数据变成响应式对象,其中的getter部分便是用来收集的。
    初始化最终会走mount过程,其中会实例化watcher,进入watcher中,便会执行this.get()方法 ```javascript updateComponent = ()=>{ vm._update(vm._render()) }

new Watcher(vm,updateComponent) ``` get方法中的pushTarget实际上就是把Dep.target赋值为当前的watcher,this.getter.call(vm,vm),这里的getter会执行vm._render()方法,在这个过程中便会触发数据对象的getter
那么每个对象值的getter都持有一个dep,在触发getter的时候会调用dep.depend()方法,也就是会执行Dep.target.addDep(this)
刚才Dep.target已经被赋值为watcher,于是就执行addDep方法,然后走到dep.addSub()方法,便将当前的watcher订阅到这个数据持有的dep的subs中,这个是为了后续数据变化的时候能通知到哪些subs做准备
所以在vm._render()过程中,会触发所有的数据的getter,这样已经完成了一个依赖收集的过程