vue数据响应式原理(三)__Vue.js
粉丝福利 : 关注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