Vue数据绑定简析小结(7)

if (inserted) ob.observeArray(inserted)
// notify change
ob.dep.notify()

将其转换为响应式数据,并通过 ob.dep.notify 来调用观察者的方法,而这里的观察者列表就是通过上述的 childOb.dep.depend 来收集的。同样的,为了实现对象新增数据的响应式,我们需要提供相应的 hack 方法,而这就是我们常用的 Vue.set/Vue.delete 。

// src/core/observer/index.js
export function set (target: Array<any> | Object, key: any, val: any): any {
 ...
 if (Array.isArray(target) && isValidArrayIndex(key)) {
  target.length = Math.max(target.length, key)
  target.splice(key, 1, val)
  return val
 }
 if (key in target && !(key in Object.prototype)) {
  target[key] = val
  return val
 }
 const ob = (target: any).__ob__
 if (target._isVue || (ob && ob.vmCount)) {
  process.env.NODE_ENV !== 'production' && warn(
   'Avoid adding reactive properties to a Vue instance or its root $data ' +
   'at runtime - declare it upfront in the data option.'
  )
  return val
 }
 if (!ob) {
  target[key] = val
  return val
 }
 defineReactive(ob.value, key, val)
 ob.dep.notify()
 return val
}
  • 判断value是否为数组,如果是,直接调用已经hack过的splice即可。
  • 是否已存在key,有的话说明已经是响应式了,直接修改即可。
  • 接着判断target.__ob__是否存在,如果没有说明该对象无须深度观察,设置返回当前的值。
  • 最后,通过defineReactive来设置新增的key,并调用ob.dep.notify通知到观察者。

现在我们了解了 childOb.dep.depend() 是为了将当前 watcher 收集到 childOb.dep ,以便在增、删数据时能通知到 watcher 。而在 childOb.dep.depend() 之后还有:

if (Array.isArray(value)) {
  dependArray(value)
}
/**
 * Collect dependencies on array elements when the array is touched, since
 * we cannot intercept array element access like property getters.
 */
function dependArray (value: Array<any>) {
 for (let e, i = 0, l = value.length; i < l; i++) {
  e = value[i]
  e && e.__ob__ && e.__ob__.dep.depend()
  if (Array.isArray(e)) {
   dependArray(e)
  }
 }
}

在触发 target[key] 的 getter 时,如果 value 的类型为数组,则递归将其每个元素都调用 __ob__.dep.depend ,这是因为无法拦截数组元素的 getter ,所以将当前 watcher 收集到数组下的所有 __ob__.dep ,这样当其中一个元素触发增、删操作时能通知到观察者。比如:

const data = {
  list: [[{value: 0}]],
};
data.list[0].push({value: 1});

这样在 data.list[0].__ob__.notify 时,才能通知到 watcher 。

target[key] 的 getter 主要作用:

将 Dep.target 收集到闭包中 dep 的观察者列表,以便在 target[key] 的 setter 修改数据时通知观察者

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/385.html