通过 Vue.set 设置对象 一个新的属性时所发生的事情

来源:4-10 检测变化的注意事项

aznmoe

2020-02-13

老师你好,这里我打断点的时候 有点乱,不能理清,我从代码角度去理解下这个过程你看看对不对。

Vue.set 函数 可以直接简化为以下两个语句

defineReactive(ob.value, key, val);
ob.dep.notify();

假设 vm._data{msg: {a: 'aaa'}},那么在初始化完毕后,vm._datavm._data.msg 都会被 new Observe() 即 两者都会有一个 __ob__ 属性。 且 vm._data.msg 通过 childOb.dep.depend() 使 vm._data.msg.__ob__.dep.subs 收集了 当前的 渲染watcher

  1. 一般情况下 vm._data.msg.a = 'newValaaa' 时,其会直接 触发 vm._data.msg.a 所持有的 dep.notify。也就是上两节课所讲的内容。
  2. Vue.set(vm._data.msg, 'b', 'bbb') 时,这个时候在 Vue.set 函数内部执行 vm._data.msg.__ob__.dep.notify 去。为什么要这样?
    因为 vm._data.msg.b 在没有被 defineReactive过呢还(等下说 Vue.set 里面那个 defineReactive),我们只能退而求其次,让 vm._data.msg.b 的父级 vm._data.msgnotify。因为 vm._data.msg.__ob__.subs 含有当前的 渲染 watcher,随后便可 成功的渲染新的页面了。
    提问: 如果 我们能在 Vue.set 函数中 拿到 vm 实例的话,是不是 我们直接 vm._data.__ob__.dep.notify 理论上也能完成更新?

回过头来说 Vue.set 函数中 defineReactive(ob.value, key, val); 作用,其作用其实很简单,就是为 vm._data.obj 的 新属性 弄成响应式的,但其还未被读取过,也就是说 这个属性 所持有的 dep.subs 数组为空


总结下,我的观点是 childOb.dep.depend() 是 为 vm._data 下的 每一个层级的对象 做一个依赖收集,这个收集的目的是 好 手动 dep.notify 去,然后 用到这个的就是 Vue.set,所有老师说 childOb.dep.depend() 就是 为 Vue.set 而准备的

写回答

1回答

ustbhuangyi

2020-02-13

你理解的没有问题,先为你点赞。

提问: 如果 我们能在 Vue.set 函数中 拿到 vm 实例的话,是不是 我们直接 vm._data.__ob__.dep.notify 理论上也能完成更新?

是的,但是不如 ob.dep.notify() 更直观,先定义成响应式,再主动触发响应式对象依赖的通知。

0
1
aznmoe
非常感谢!
2020-02-14
共1条回复

Vue.js 源码深入解析 深入理解Vue实现原理

全方位讲解 Vue.js 源码,进阶高级工程师

4986 学习 · 1038 问题

查看课程