关于vue2响应式中Dep类的浅见

76 阅读2分钟

前言

之前学习vue时看过部分源码,当时只是大概了解了一下vue响应式原理,还有diff算法和VNode那块,
最近稍微有点空,正好回过头来再细细过下。

正文

 看过vue源码的各位大佬从标题应该就能看出来这篇内容水什么,/手动狗头/....。
 首先我们知道Dep类的作用就是存放依赖,它负责收集依赖,并且当数据发值发生变化后通知Watcher更新,
 so 我们每一个响应式的值都需要一个Dep实例,/无图言diao/...。我就贴下这块相关代码。
export default function defineReactive(data, key, val) {

  //闭包保存的Dep类
    const dep = new Dep();
    console.log(dep,key)
    if (arguments.length == 2) {
        val = data[key];
    }
    // 子元素要进行 observe, 至此形成了递归,
    // 这个递归不是函数自己调用自己
   
    let childOb = observe(val); //Observer对象保存下来

    Object.defineProperty(data, key, {
        // 可枚举
        emuerable: true,
        // 可以被配置,比如可以被 delete
        configurable: true,
        get() {

            console.log(`正在访问${key}属性`, val);
            // 如果现在处于依赖收集阶段
            if (Dep.target) {
              dep.depend();
            
            if (childOb) {
              childOb.dep.depend();        //利用childOb对象上的dep去收集一次依赖
            }
          }
            return val;
        },

        set(newValue) {

            console.log(`正在改变${key}属性`, newValue);

            if (val === newValue) { return };
            val = newValue;
            // 当设置了新值,新值也要 observe
            childOb = observe(newValue);

            // 发布订阅模式
            dep.notify();
        }
    })
} 

//Observer类
class Observer {
  constructor(value) {
    this.dep = new Dep()
    def(value, '__ob__', this, false)
    if (Array.isArray(value)) {
      // ...
    } else {
      // ...
    }
  }
  // ...
}

再每次执行defineReactive方法将一个键值变成响应式时,都会利用闭包保存它的dep,也就是上面的 const dep = new Dep()然后在下面触发get的时候进行依赖收集。这时候有人可能已经发现了,Observer类构造器中也会实例化一个dep对象来保存依赖,那它两都起作用还是???

继续看defineReactive,我们可以看到拿到当前key对应的值后对他进行响应式处理,并将返回的observer对象赋给了childOb,可以看出在触发依赖收集的时候,不光对当前入参的key的依赖列表进行收集,还对对应值的依赖列表进行收集;那这与childOb对象上的dep.append在收集一次有什么关系呢?

讲到这里我举个栗子吧

gg