Vue的响应式原理-两个创建Dep的位置

22 篇文章 0 订阅
9 篇文章 0 订阅
本文解析Vue响应式原理中的Observer创建的Dep与defineReactive中的Dep的区别:前者用于对象属性增删时通知,后者在定义可反应属性时收集依赖。讲解了它们在数组更新和对象属性操作中的作用。
摘要由CSDN通过智能技术生成

需要您明白大致的Vue响应式原理相关知识ObserverDepWatcher

问题:

Vue响应式的class Observer部分,我们发现会有两个部分都创建了Dep实例

export class Observer {
  constructor (value: any) {
    this.value = value
    this.dep = new Dep() // 第一个创建的dep----------------------------------
    this.vmCount = 0
    def(value, '__ob__', this)
    ...
    }
    ...
}

...

export function defineReactive (obj, key, val, customSetter, shallow) {
  const dep = new Dep() // 第二个创建的dep----------------------------------
  const property = Object.getOwnPropertyDescriptor(obj, key)
  if (property && property.configurable === false) {
    return
  }
  ...
}

那么这两个dep到底都是干什么用的呢?


分别解答:

defineReactive - dep

我们先说defineReactive中的dep,这个dep是闭包在defineReactive函数中的,无法直接从data的属性中直接捕获到该dep,他的订阅/触发位置是在Object.defineProperty中的get/set里触发的
这个实例的作用很明显,是用于对象增加/删除属性时而被调用的

Observer - dep

这个depObserver创建一开始就被实例化,而且他和上边的dep不同,他被绑定在Observer的实例上,也就是在外界同样可以取到他

这个dep大多情况下是给数组使用,具体使用地方见下方:

  1. 数组更新的watcher收集

以一个例子说明:

new Vue({
    data() {
        return {
            arr: [1,2,3,4],
            a: 'xxx',
            b: ...
            ...
        }
    },
    ...
})

在初始化阶段,data中的所有数据都会被递归进行响应式代理,data中数组的数据也会被 option.data(用户传的data)本身也会被代理
**在渲染阶段,获取data中的数组(arr:[...])时,**会执行Object.defineProperty(data,'arr',fun)所代理的get方法,在其中会调用childOb.dep.depend()方法,对该dep收集依赖

此处说明childOb.dep.depend()方法位置

function defineReactive (...) {
    const dep = new Dep()
    ...
    let childOb = !shallow && observe(val)
     Object.defineProperty(obj, key, {
    enumerable: true,
    configurable: true,
    // 提示:get中的内容是在运行阶段执行的,创建Observer、dep实例是在渲染时就已经生成的
    get: function reactiveGetter () {
      const value = getter ? getter.call(obj) : val
      if (Dep.target) {
        dep.depend()
        if (childOb) {
          // ↓就是这句话,此处的childOb指的就是arr的Observer实例
          childOb.dep.depend()
          if (Array.isArray(value)) {
            dependArray(value)
          }
        }
      }
      return value
    },
}
  1. 数组的修改
    数组是没有Object.defineProperty的,Vue中修改数组数据,采用的是代理数组中的方法(push,pop,shift,unshift,splice,sort,reverse)来达到响应式的目的,而在这7个Vue代理过的函数中,通知watcher更新就是调用的这个dep
// 截取代码片段
const methodsToPatch = ['push','pop','shift','unshift','splice','sort','reverse']
methodsToPatch.forEach(function (method) {
  def(arrayMethods, method, function mutator (...args) {
    const result = original.apply(this, args) 
    const ob = this.__ob__ 
    let inserted
    switch (method) {
      case 'push':
      case 'unshift':
        inserted = args
        break
      case 'splice':
        inserted = args.slice(2)
        break
    }
    if (inserted) ob.observeArray(inserted)
    // ↓这里的更新就是调用的数组的Observer -> dep中的notify
    ob.dep.notify()
    return result
  })
})
  1. set方法/delete方法
    使用set、delete方法为对象中赋值新的属性时,调用的ob.dep.notify()就是targetObserver - dep.notify
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值