实现一个watcher
v.$watch("a",()=>console.log("哈哈,$watch成功"))
export default class Watcher {
constructor(vm, expOrFn, cb) {
this.cb = cb
this.vm = vm
//此处简化.要区分fuction还是expression,只考虑最简单的expression
this.expOrFn = expOrFn
this.value = this.get()
}
update(){
this.run()
}
run(){
const value = this.get()
if(value !==this.value){
this.value = value
this.cb.call(this.vm)
}
}
get(){
//此处简化。。要区分fuction还是expression
const value = this.vm._data[this.expOrFn]
return value
}
}
那么问题来了,我们怎样将通过addSub(),将Watcher加进去呢。
我们发现var dep = new Dep() 处于闭包当中,我们又发现Watcher的构造函数里会调用this.get。所以,我们可以在上面动动手脚,修改一下Object.defineProperty的get要调用的函数,判断是不是Watcher的构造函数调用,如果是,说明他就是这个属性的订阅者。果断将他addSub()中去,那问题来了,我怎样判断他是Watcher的this.get调用的,而不是我们普通调用的呢。对,在Dep定义一个全局唯一的变量,跟着思路我们写一下
export default class Watcher {
  ....省略未改动代码....
  get(){
    Dep.target = this
    //此处简化。。要区分fuction还是expression
    const value = this.vm._data[this.expOrFn]
    Dep.target = null
    return value
  }
}
这样的话,我们只需要在Object.defineProperty的get要调用的函数里,判断有没有值,就知道到底是Watcher 在get,还是我们自己在查看赋值,如果是Watcher的话就addSub(),代码补充一下
export function defineReactive (obj, key, val) {
  var dep = new Dep()
  var childOb = observe(val)
  Object.defineProperty(obj, key, {
    enumerable: true,
    configurable: true,
    get: ()=>{
      // 说明这是watch 引起的
      if(Dep.target){
        dep.addSub(Dep.target)
      }
      return val
    },
    set:newVal=> {
      var value =  val
      if (newVal === value) {
        return
      }
      val = newVal
      childOb = observe(newVal)
      dep.notify()
    }
  })
}
最后不要忘记,在DEP.js中加上这么一句
Dep.target = null
4.实现一个vue
import Watcher from '../watcher'
import {observe} from "../observer"
export default class Vue {
  constructor (options={}) {
    //这里简化了。。其实要merge
    this.$options=options
    //这里简化了。。其实要区分的
    let data = this._data=this.$options.data
    Object.keys(data).forEach(key=>this._proxy(key))
    observe(data,this)
  }
  $watch(expOrFn, cb, options){
    new Watcher(this, expOrFn, cb)
  }
  _proxy(key) {
    var self = this
    Object.defineProperty(self, key, {
      configurable: true,
      enumerable: true,
      get: function proxyGetter () {
        return self._data[key]
      },
      set: function proxySetter (val) {
        self._data[key] = val
      }
    })
  }
}
转载请注明: Vue教程中文网 - 打造国内领先的vue学习网站-vue视频,vue教程,vue学习,vue培训 » vue源码分析之实现observer和watcher(二)

