在哪里收集
data(){
return {
arr:[1,2,3]
}
}
要用到arr这个数据,是不是得先从object数据对象中获取一下arr数据,而从object数据对象中获取arr数据自然就会触发arr的getter,所以我们就可以在getter中收集依赖
Array型数据还是在getter中收集依赖。
观测Array发生变化
改写数组原型链上的方法
const arrayProto = Array.prototype
/* 继承自Array原型的对象 */
export const arrayMethods = Object.create(arrayProto)
const methodsToPatch = [
'push',
'pop',
'shift',
'unshift',
'splice',
'sort',
'reverse'
]
/**
* Intercept mutating methods and emit events
*/
/* def 作用是定义一个property */
methodsToPatch.forEach(function (method) {
// cache original method
const original = arrayProto[method]
/* 将7个方法逐个封装 */
def(arrayMethods, method, function mutator (...args) {
/* 执行了原生方法 */
const result = original.apply(this, args)
const ob = this.__ob__
/*
可以向数组内新增元素的方法有3个,分别是:push、unshift、splice。
我们只需对这3中方法分别处理,拿到新增的元素,再将其转化即可
为什么要写下面这个代码,因为我们新增的元素可能是对象,
我们要深度侦测这个对象
*/
let inserted
switch (method) {
case 'push':
case 'unshift':
inserted = args
break
case 'splice':
inserted = args.slice(2)
break
}
if (inserted) ob.observeArray(inserted)
/*
这里很关键, 通知watcher更新
*/
ob.dep.notify()
return result
})
})
Observer
/*
开始判断数据的类型
只有object类型的数据才会调用walk将每一个属性转换成getter/setter的形式来侦测变化
注意这里,因为Object.defineProperty 是针对对象的,数组是无法使用这个方法的
所以,走的是另外的变化机制
*/
if (Array.isArray(value)) {
// 判断对象上是否有原型,也就是说,判断浏览器支持原型链不
if (hasProto) {
// 把方法放在这个数组的原型链上
// 其实是改写了这个数组上的方法,这样的话使用push就会变化
/*
把重写的一些方法,挂载到数组的原型链上
*/
protoAugment(value, arrayMethods)
} else {
copyAugment(value, arrayMethods, arrayKeys)
}
// 对数组深度侦测
this.observeArray(value)
} else {
// data 是个对象
// 给每个属性加上响应式
this.walk(value)
}
}
/**
* 对数组深度侦测,如果数组的元素是对象,也能侦测到
*/
observeArray (items: Array<any>) {
for (let i = 0, l = items.length; i < l; i++) {
/* 给那些元素是对象的item,加上Observer */
observe(items[i])
}
}