traverse
方法用来深度收集依赖。
ts
// 1. 深度监听
vm.$watch('someObject', callback, {
deep: true // 会调用 traverse
})
// 2. 复杂数据结构
const data = {
user: {
profile: {
address: {
city: 'NY'
}
}
},
items: [
{ id: 1, name: 'item1' },
{ id: 2, name: 'item2' }
]
}
// traverse(data) 会:
// - 访问 user.profile.address.city
// - 访问 items[0].id 和 items[0].name
// - 访问 items[1].id 和 items[1].name
ts
const seenObjects = new Set()
export function traverse(val: any) {
_traverse(val, seenObjects)
seenObjects.clear()
return val
}
function _traverse(val: any, seen: SimpleSet) {
let i, keys
const isA = isArray(val)
if (
(!isA && !isObject(val)) ||
val.__v_skip /* ReactiveFlags.SKIP */ ||
Object.isFrozen(val) ||
val instanceof VNode
) {
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)
} else if (isRef(val)) {
_traverse(val.value, seen)
} else {
keys = Object.keys(val)
i = keys.length
while (i--) _traverse(val[keys[i]], seen)
}
}