vue数据响应式原理(三)__Vue.js
发布于 4 年前 作者 banyungong 1745 次浏览 来自 分享
粉丝福利 : 关注VUE中文社区公众号,回复视频领取粉丝福利

前言

vue数据响应式原理(二)中已经实现了对象类型的依赖收集和依赖更新的。本节内容继续描述数据的依赖收集和依赖更新。

数组依赖收集

对于一个对象,是给每一个对象的属性定义了一个dep。而对于数组,则是给整个数组定义了一个dep。只要触发了这个数组的那七个方法,就会触发数据更新。

class Observer {
  constructor(value) {
    this.dep = new Dep()
    // 判断一个对象是不是被观测过,看他是否有__ob__这个属性
    defineProperty(value,'__ob__',this); // Object.keys获取不到这个key值 就不会导致死循环
    ...
    }
  }

上面的代码表示:在进行数据观测的时候,给每一个对象(无论是对象还是数组),都会创建一个dep属性。

function defineReactive(data,key,value) {
  // 获取到数组对应的dep
  let childDep = observe(value)  // 如果值是对象再进行观测
  let dep = new Dep(); // 每个属性都有一个dep
  Object.defineProperty(data,key,{
    get() { // 依赖收集
      if(Dep.target) { //让这个属性记住这个watcher
        dep.depend();
        if(childDep){
          childDep.dep.depend();
        }
      }
      return value
    },
    set(newValue) { // 依赖更新
      if(newValue == value) return;
      observe(newValue) // 如果用户将值设置为对象仍然需要进行观测
      value = newValue;
      dep.notify();
    }
  })
}

因此在childDep上就会存在dep属性,然后继续调用depend进行依赖收集。

数组依赖更新

在数组的数据劫持部分,被劫持对象上存在__ob__属性,所指向的正是observe实例,因此可以获取到数组的dep属性,触发notify进行数据更新。

methods.forEach(method => {
  arrayMethods[method] = function (...args) {
    // 当调用数组劫持的方法,页面更新
    const result = oldArrayProtoMethods[method].apply(this,args); // this 就是observer里的value
    let inserted;
    let ob = this.__ob__;
    switch(method) {
      case 'push':  // arr.push({a:1},{b:2})
      case 'unshift': // 追加数据  可能是对象 应该再次被劫持
        inserted = args;
        break;
      case 'splice': // vue.$set原理
        inserted = args.slice(2);
      default:
        break;
    }
    if(inserted) ob.observeArray(inserted) // 新增对象也被观测了
    ob.dep.notify() // 通知更新
    return result;
  }
})

总结

数组依赖收集和依赖更新的整个过程:

1.取arr的值会调用get方法,让当前数组记住这个渲染watcher 2.给所有的对象类型都加一个dep属性 3.当页面对arr取值时,让数组的dep记住这个watcher 4.更新数组时,找到对应的watcher更新

版权声明:著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 作者: 知识的搬运工 原文链接:https://juejin.im/post/6869240027843559438

回到顶部