Appearance
deep
javascript
// 深度监视,如果监视的属性值是数组或对象,那么数组或对象所有层次的对象的属性都会被监视,
// 只需要让这些属性的 dep 都收集 user watcher 即可。Watcher 类的 get 方法中
// this.getter() 执行完后第一层对象的属性的 dep 就收集完 user watcher 了。
// 之后判断一下 this.deep 是否为真,为真说明进行深度监视,调用 traverse(val) 遍历该数
// 据的对象的所有层次的属性,如果 val 不是数组也不是对象,直接返回,它没有下一层。
// 否则取出 val.__ob__.dep.id,如果 Set 中有,说明该数组或对象处理过了,直接返回。
// 如果是对象,对每一项递归调用 traverse(val[keys[i]]),由于取值了,触发
// Object.defineProperty 中的 get,让这个属性的 dep 收集到了 user watcher,
// 如果 value 是数组和对象,又会进行下一轮递归,实现对象所有层次的对象的属性的 dep
// 收集到 user watcher。
// 如果是数组,对每一项递归调用 traverse(val[i]),如果某一项是对象,就能通过上面的
// 逻辑现对象所有层次的对象的属性的 dep 收集到 user watcher。
get () {
pushTarget(this)
let value
const vm = this.vm
try {
value = this.getter(vm)
} catch (e) {
// ...
} finally {
if (this.deep) {
traverse(value) // 遍历该数据所有层次的属性, 让它们收集user watcher
}
popTarget()
}
return value
}
const seenObjects = new Set()
function traverse (val) {
_traverse(val, seenObjects)
seenObjects.clear()
return val
}
function _traverse (val, seen) {
let i, keys
const isA = Array.isArray(val)
if (!isA && !isObject(val)) { // 基本类型
return
}
if (val.__ob__) { // 响应式的数据
const depId = val.__ob__.dep.id
if (seen.has(depId)) { // 处理过了
return
}
seen.add(depId)
}
if (isA) {
i = val.length
while (i--) {
_traverse(val[i], seen) // 取值 => 对象触发get => dep收集user watcher
}
} else {
keys = Object.keys(val)
i = keys.length
while (i--) {
_traverse(val[keys[i]], seen)
}
}
}