Vue2.x的数据绑定是通过数据劫持的方式来实现的,其中最核心的便是Object.defineProperty(),而Vue3.0里面数据绑定是通过Proxy实现的

Vue2.x的双向数据绑定,有三个比较核心的部分

Observer:通过Object.defineProperty来做数据劫持,递归地监听对象上的所有属性,在属性值改变的时候,触发相应的Watcher

Watcher:订阅者,当监听的数据值修改时,执行通知Dep执行对应的响应的回调函数

Dep:将ObserverWatcher关联起来,这个双向数据绑定实现的设计模式为发布订阅模式,Dep就相当于发布订阅模式的中间对象

Observer

export class Observer {
  value: any;
  dep: Dep;
  vmCount: number; // number of vms that have this object as root $data

  constructor (value: any) {
    this.value = value
    this.dep = new Dep()
    this.vmCount = 0
    // 通过Object.defineProperty设置_ob_值,使用_ob_可以直接拿到Observer对象
    def(value, '__ob__', this)
    if (Array.isArray(value)) {
      if (hasProto) {
        protoAugment(value, arrayMethods)
      } else {
        copyAugment(value, arrayMethods, arrayKeys)
      }
      // 如果是数组,调用observeArray处理
      this.observeArray(value)
    } else {
      // 如果是其他对象调用walk处理
      this.walk(value)
    }
  }

  walk (obj: Object) {
    const keys = Object.keys(obj)
    // 遍历对象属性,对每个属性添加数据邦数据绑定
    for (let i = 0; i < keys.length; i++) {
      defineReactive(obj, keys[i])
    }
  }

  observeArray (items: Array<any>) {
    // 如果是数组,则循环遍历数组,调用observe
    for (let i = 0, l = items.length; i < l; i++) {
      observe(items[i])
    }
  }
}

defineReactive

export function defineReactive (
  obj: Object,
  key: string,
  val: any,
  customSetter?: ?Function,
  shallow?: boolean
) {
  const dep = new Dep()
	
  // 获取obj上对应属性key的描述符,如果configurable为false,属性不能改变,return
  const property = Object.getOwnPropertyDescriptor(obj, key)
  if (property && property.configurable === false) {
    return
  }

  const getter = property && property.get
  const setter = property && property.set
  if ((!getter || setter) && arguments.length === 2) {
    val = obj[key]
  }

  let childOb = !shallow && observe(val)
  Object.defineProperty(obj, key, {
    enumerable: true,
    configurable: true,
    get: function reactiveGetter () {
      // 获取这个值
      const value = getter ? getter.call(obj) : val
      if (Dep.target) {
        // 将当前dep添加到target中,然后将dep添加到subs中	
        dep.depend()
        if (childOb) 
          childOb.dep.depend()
          if (Array.isArray(value)) {
						// 如果传入的值为数组,遍历这个数组,对每一个元素depend
            dependArray(value)
          }
        }
      }
      return value
    },
    set: function reactiveSetter (newVal) {
    	// 获取对象原来的值
      const value = getter ? getter.call(obj) : val
      // 如果新设置的值和原来的值一样,直接return
      if (newVal === value || (newVal !== newVal && value !== value)) {
        return
      }
    	// 打印错误
      if (process.env.NODE_ENV !== 'production' && customSetter) {
        customSetter()
      }
    	// 若属性上设置了getter没设置setter,return
      if (getter && !setter) return
      if (setter) {
        setter.call(obj, newVal)
      } else {
        // 设置新的值
        val = newVal
      }
    	// 创建一个新的observe,并触发对应的更新事件
      childOb = !shallow && observe(newVal)
      dep.notify()
    }
  })
}

observe这个方法主要是返回与对象相关的Observer对象,如果没有,则新创建一个Observer对象并返回

defineReactive中还有几个方法,protoAugmentcopyAugment

var arrayProto = Array.prototype
var arrayMethods = Object.create(arrayProto)
function protoAugment (target, src) {
  target.__proto__ = src;
}
protoAugment(value, arrayMethods)

对于数组对象来说在当前环境如果能使用__proto__对象(__proto__ in {}),则调用protoAugment,其实就是将当前的数组对象__proto__指向数组原型对象,然后对于pushpopshiftunshiftsplicesortreverse这些操作数组的方法,遍历,添加到arrayMethods上,操作之后,调用ob.dep.notify()触发更新

copyAugment则是在循环中把arrayMethods上的arrayKeys方法添加到value

Dep

Dep的定义比较简单,就是简单的保存了一个Wacher数组,有一些增删的方法,最后notify调用对应Wacher更新的方法

export default class Dep {
  static target: ?Watcher;
  id: number;
  subs: Array<Watcher>;

  constructor () {
    this.id = uid++
    this.subs = []
  }

  addSub (sub: Watcher) {
    this.subs.push(sub)
  }

  removeSub (sub: Watcher) {
    remove(this.subs, sub)
  }

  depend () {
    if (Dep.target) {
      Dep.target.addDep(this)
    }
  }

  notify () {
    const subs = this.subs.slice()
    if (process.env.NODE_ENV !== 'production' && !config.async) {
      subs.sort((a, b) => a.id - b.id)
    }
    for (let i = 0, l = subs.length; i < l; i++) {
      subs[i].update()
    }
  }
}

Watcher

export default class Watcher {
	......
  constructor (
    vm: Component,
    expOrFn: string | Function,
    cb: Function,
    options?: ?Object,
    isRenderWatcher?: boolean
  ) {
    this.vm = vm
    if (isRenderWatcher) {
      vm._watcher = this
    }
    vm._watchers.push(this)
    // 创建Watcher时传的options
    // 如之前调用updateComponet方法时,传入before来调用beforeUpdate钩子函数
    if (options) {
      this.deep = !!options.deep
      this.user = !!options.user
      this.lazy = !!options.lazy
      this.sync = !!options.sync
      this.before = options.before
    } else {
      this.deep = this.user = this.lazy = this.sync = false
    }
    this.cb = cb
    this.id = ++uid 
    this.active = true
    this.dirty = this.lazy 
    this.deps = []
    this.newDeps = []
    this.depIds = new Set()
    this.newDepIds = new Set()
    this.expression = process.env.NODE_ENV !== 'production'
      ? expOrFn.toString()
      : ''
    
    // 设置getter
    // 如果传入expOrFn是一个函数
    if (typeof expOrFn === 'function') {
      this.getter = expOrFn
    } else {
      // 如果传入的不是一个函数,通过parsePath解析,赋值给getter
      this.getter = parsePath(expOrFn)
      if (!this.getter) {
        // 如果解析出来的getter不是一个函数,设置为空 noop,并打印错误
        this.getter = noop
        process.env.NODE_ENV !== 'production' && warn(
          `Failed watching path: "${expOrFn}" ` +
          'Watcher only accepts simple dot-delimited paths. ' +
          'For full control, use a function instead.',
          vm
        )
      }
    }
    this.value = this.lazy
      ? undefined
      : this.get()
  }

  /**
   * Evaluate the getter, and re-collect dependencies.
   */
  get () {
    // 设置Dep.tartget为当前watcher,这样它就有addSub、removeSub等方法
    pushTarget(this)
    let value
    const vm = this.vm
    try {
      // 得到调用getter的value
      value = this.getter.call(vm, vm)
    } catch (e) {
      if (this.user) {
        handleError(e, vm, `getter for watcher "${this.expression}"`)
      } else {
        throw e
      }
    } finally {
      if (this.deep) {
        traverse(value)
      }
      // 清楚Dep,移出target队列,重新设置Dep.target值
      popTarget()
      this.cleanupDeps()
    }
    
    // 在进行模板渲染的时候,value为undefined
    return value
  }
	
	......
	
  // 在更新数据时,调用dep.notify,会触发update方法
  update () {
    if (this.lazy) {
      this.dirty = true
    } else if (this.sync) {
      // 若生成Watcher传入配置sync
      // 在更新的时候直接调用run方法,调用回掉方法
      this.run()
    } else {
      // 如果不是sync配置,处理Watcher队列
      // queueWatcher方法里会使用一个id来表示Watcher的优先级,依次执行上面的run方法
      // 更新的时候如果watcher列表正在更新,则把新的watcher添加到对应的位置,并更新
      // 否则,在下一个nextTick中执行flushSchedulerQueue
      queueWatcher(this)
    }
  }

  run () {
    if (this.active) {
      const value = this.get()
      if (
        value !== this.value ||
        isObject(value) ||
        this.deep
      ) {
        const oldValue = this.value
        this.value = value
        if (this.user) {
          try {
            this.cb.call(this.vm, value, oldValue)
          } catch (e) {
            handleError(e, this.vm, `callback for watcher "${this.expression}"`)
          }
        } else {
          // 回调
          this.cb.call(this.vm, value, oldValue)
        }
      }
    }
  }
	
	......
}