Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Vue为什么要实例Observer对象,并带有dep属性? #17

Open
LeeeeeeM opened this issue Dec 10, 2018 · 0 comments
Open

Vue为什么要实例Observer对象,并带有dep属性? #17

LeeeeeeM opened this issue Dec 10, 2018 · 0 comments

Comments

@LeeeeeeM
Copy link
Owner

Vue为什么要实例一个Observer对象,而每一个Observer对象都挂有三个属性:value(原始数据)、vmCount(number of vms that have this object as root $data,被VM作为根数据的个数)、dep。起初我以为这个dep这个属性对于所有的observer都有用。直到后来看了好几遍Vue源码才体会到并非起初想得那样。劫持数据的过程:vm上先得到一个_data属性,将需要劫持的数据挂上去。类似于以下代码:

data()  {
    return {
        name: {
           cc: 'slm'
        }   
    }
}

得到_data差不多是{name: {cc: 'slm'}},然后走observe方法,判断当前对象(_data)是否存在__ob__属性,如果存在,则说明已经被劫持过了,不需要再劫持处理了。没有则实例话一个Observer对象(满足条件一般是对象或数组)。第一次的话实例一个Observer对象。先在当前对象(或数组)def一个__ob__属性,用于标记并存放当前的value,这个属性之后的操作几乎不用。接下来就要对该对象或者数组遍历并做劫持了。walk -> defineRactive 劫持。重头戏来了:

function defineReactive()  {
    ///
    const dep = new Dep() 这是一个闭包,其实这里的dep才是最终要使用的依赖收集器
    ///
    // cater for pre-defined getter/setters  预处理getter和setter
    // 正戏
    let childOb = !shallow && observe(val)   // warnin~!!!! 这里很重要,我们都知道js中的对象是引用地址的,只要对象引用的地址不变,那么该对象就不变。
    Object.defineProperty(obj, key, {
        enumerable: true,
        configurable: true,
        get: function reactiveGetter () {
              const value = getter ? getter.call(obj) : val
              if (Dep.target) {
                    dep.depend()   // dep作为闭包,收集依赖该value的watcher,用于UI更新或者数据跟踪。
                    if (childOb) {
                          childOb.dep.depend()    // warning~!!!! 这里很重要,为什么依赖子属性的watcher也要订阅呢???这是因为如果该值发生了变化,即在set的时候发生变化,执行notify,那么该对象的子属性肯定也变化了,这个是毫无疑问的,所以这里子属性的依赖收集器也必须订阅一下。 warning,那么这里似乎我们对文章开头的时候提出的疑问似乎可以解答了,为什么Vue要实例Observer并使其有dep属性?实例化的原因不说了,面向对象的思想。为什么dep属性要挂到对象上呢??不是都放到这个空间的闭包里面吗?回答:因为需要子属性的引用,这里childOb.dep就是为了对依赖收集器的引用,所以挂到了Observer的实例上,所有有的人很懵,为什么又是闭包有挂到实例属性上...
                          if (Array.isArray(value)) {
                              dependArray(value)
                          }
                    }
              }
              return value
           },
        set: function reactiveSetter (newVal) {
          const value = getter ? getter.call(obj) : val

          if (newVal === value || (newVal !== newVal && value !== value)) {
            return
          }

          if (process.env.NODE_ENV !== 'production' && customSetter) {
            customSetter()
          }

          if (getter && !setter) return
          if (setter) {
            setter.call(obj, newVal)
          } else {
            val = newVal
          }
          childOb = !shallow && observe(newVal)  /// 赋值之后重新Observe劫持数据
          dep.notify() // 触发一次notify,搞事情(更新等)
        }
      })
    }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant