Skip to content

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)
  }
}