Skip to content

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