初始化数据
// TODO: 初始化数据function initData (vm: Component) {  let data = vm.$options.data  // data 是不是函数,是函数就让他执行获取数据 挂到 vm._data  data = vm._data = typeof data === 'function'    ? getData(data, vm)    : data || {}  // 观测数据  observe(data, true /* asRootData */)}
观测数据
/** * 响应式处理的真正入口 * 为对象创建观察者实例,如果对象已经被观察过,则返回已有的观察者实例,否则创建新的观察者实例 * @param {object} value  * @param {boolean} asRootData  * @returns  */export function observe (value, asRootData){  // 如果是对象并且不是 vnode 的时候才观测  if (!isObject(value) || value instanceof VNode) {    return  }  let ob  // value 对象上存在 __ob__ 属性,则表示已经做过观察了,直接返回 __ob__ 属性  if(hasOwn(value, '__ob__') && value.__ob__ instanceof Observer){    ob = value.__ob__  }  if (    shouldObserve &&    !isServerRendering() && // 是否需要被观测    (Array.isArray(value) || isPlainObject(value)) && // 是一个数组或对象    Object.isExtensible(value) && // 支持 defineProperty    !value._isVue // 不是vue 实例  ) {    // 创建观察者实例    ob = new Observer(value)   }  // 记录观测数量  if (asRootData && ob) {    ob.vmCount++   }  return ob}
创建观察者实例
/** * 2.观察者类,会被附加到每个被观察的对象上,value.__ob__ = this * 而对象的各个属性则会被转换成 getter/setter,并收集依赖和通知更新 */export class Observer {  constructor (value) {    this.value = value   // ob.value    this.dep = new Dep() // 给对象和数组实例化一个 dep 属性 $set 之后就会触发他们自己的 update 方法    this.vmCount = 0    // data.__ob__ = this     // 将当前 Observer 实例挂载到 data 上 __ob__ 主要是用来取一些方法,这样被劫持过的所有属性都有 __ob__    def(value, '__ob__', this)  // 不可枚举 TODO:     /**       * value 为数组       * hasProto = '__proto__' in {}       * 用于判断对象是否存在 __proto__ 属性,通过 obj.__proto__ 可以访问对象的原型链       * 但由于 __proto__ 不是标准属性,所以有些浏览器不支持,比如 IE6-10,Opera10.1       * 为什么要判断,是因为一会儿要通过 __proto__ 操作数据的原型链       * 覆盖数组默认的七个原型方法,以实现数组响应式       */    if (Array.isArray(value)) { // 数组劫持 切片编程      //  如果支持原型链      if (hasProto) {        protoAugment(value, arrayMethods)      } else {        // 不支持就拷贝一份        copyAugment(value, arrayMethods, arrayKeys)      }      // 观测数组 如果数组中的数据是对象类型,需要监控对象的变化  arr: [{name: 'dabao'}, {age: 3}]      this.observeArray(value)    } else { //  对象劫持      this.walk(value)    }  }  /**   * 遍历对象上的每个 key,为每个 key 设置响应式   * 仅当值为对象时才会走这里   */  walk (obj) {    const keys = Object.keys(obj)    for (let i = 0; i < keys.length; i++) {      defineReactive(obj, keys[i])    }  }  /**   * 遍历数组的每一项.目的是对数组中的数组和数组中的对象再次劫持,递归   */  observeArray (items) {    for (let i = 0, l = items.length; i < l; i++) {      observe(items[i])    }  }}/** * 设置 target.__proto__ 的原型对象为 src * 比如 数组对象,arr.__proto__ = arrayMethods  * @param {Array} target value * @param {object} src arrayMethods */function protoAugment (target, src) {  target.__proto__ = src}/** * 在目标对象上定义指定属性 * 比如数组:为数组对象定义那七个方法 */function copyAugment (target: Object, src: Object, keys: Array<string>) {  for (let i = 0, l = keys.length; i < l; i++) {    const key = keys[i]    def(target, key, src[key])  }}/** * Define a property. */export function def (obj: Object, key: string, val: any, enumerable?: boolean) {  Object.defineProperty(obj, key, {    value: val,    enumerable: !!enumerable,    writable: true,    configurable: true  })}
拦截 obj[key] 的读取和设置操作
/** * 拦截 obj[key] 的读取和设置操作: *   1、在第一次读取时收集依赖,比如执行 render 函数生成虚拟 DOM 时会有读取操作 *   2、在更新时设置新值并通知依赖更新 */export function defineReactive (  obj,  key,  val,  customSetter,  shallow) {  // 实例化 dep,一个 key 一个 dep  const dep = new Dep()  // 获取 obj[key] 的属性描述符,发现它是不可配置对象的话直接 return  const property = Object.getOwnPropertyDescriptor(obj, key)  // 数据必须支持 可配置 object.freeze 包装的对象 configurable 为 false  if (property && property.configurable === false) {    return  }  /**   * getter 和 setter  是为了兼容这种情况   * a: {   *    get(){},    *    set(){},   * }   */  const getter = property && property.get  const setter = property && property.set  // 不存在 getter 只有 setter  if ((!getter || setter) && arguments.length === 2) {    val = obj[key]  }  // 递归调用,处理 val 即 obj[key] 的值为对象的情况,保证对象中的所有 key 都被观察    let childOb = !shallow && observe(val)  Object.defineProperty(obj, key, {    enumerable: true,    configurable: true,    get: function reactiveGetter () {      // 取值      const value = getter ? getter.call(obj) : val      /**       * Dep.target 为 Dep 类的一个静态属性,值为 watcher,在实例化 Watcher 时会被设置       * 实例化 Watcher 时会执行 new Watcher 时传递的回调函数(computed 除外,因为它懒执行)       * 而回调函数中如果有 vm.key 的读取行为,则会触发这里的 读取 拦截,进行依赖收集       * 回调函数执行完以后又会将 Dep.target 设置为 null,避免这里重复收集依赖       */      if (Dep.target) {        // 依赖收集,在 dep 中添加 watcher,也在 watcher 中添加 dep        dep.depend()        // 有子元素 也对其进行依赖收集        if (childOb) {          // 这就是 this.key.chidlKey 被更新时能触发响应式更新的原因          childOb.dep.depend()          // 如果这个 obj[key] 是 数组,则触发数组响应式          if (Array.isArray(value)) { // 数组嵌套数组 [[]] 递归收集 arr:[[[]]] 改最里面的一层            dependArray(value) // 嵌套数组递归收集          }        }      }      return value    },    // set 拦截对 obj[key] 的设置操作    set: function reactiveSetter (newVal) {      // 旧的 obj[key]      const value = getter ? getter.call(obj) : val      // 新旧值一样直接return      if (newVal === value || (newVal !== newVal && value !== value)) {        return      }      // setter 不存在说明该属性是一个只读属性,直接 return      // #7981: for accessor properties without setter      if (getter && !setter) return      // 设置新值      if (setter) {        setter.call(obj, newVal)      } else {         val = newVal      }      // 观测这个新值, 如果赋值的是一个新对象,需要对这个新对象进行劫持      childOb = !shallow && observe(newVal)       // 依赖通知更新      dep.notify()    }  })}
创建渲染watcher
// lifecycle.js/**   * TODO:   * 实例化 渲染 Watcher   */  new Watcher(vm, updateComponent, noop, {    before () {      if (vm._isMounted && !vm._isDestroyed) {        callHook(vm, 'beforeUpdate')      }    }  }, true /* isRenderWatcher */)
watcher源码
import Dep, { pushTarget, popTarget } from './dep'// let uid = 0/** *  * 渲染watcher 每个组件是一个watcher *    Vue1 是每个差值表达式都有一个 wacher,这就导致粒度太细,追踪的依赖就太多了,很消耗内存, *    Vue2.x 和 Vue3.x 都是以整个组件为一个 Watcher,这样状态发生变化后会通知到组件,组件内部在使用虚拟dom 进行对比,降低消耗 * 计算属性、 * vm.$watch *  * expOrFn 只能是一个 以点分割的路径或者是个函数 对于渲染watcher来说这里的 expOrFn 其实就是 vm._render 生成虚拟 dom、执行 dom-diff、更新真实 dom。 * vm.$watch('a.b.c',function(newValue, oldValue) {console.log('读数据')}) * vm.$watch(function(){return data.a + data.b)},function(newValue, oldValue) {console.log('读数据')}) *  */export default class Watcher { // 希望在第一个参数发生变化时触发第二个参数中的函数  constructor (    vm,    expOrFn,    cb,    options,    isRenderWatcher  ) {    this.vm = vm // 当前组件实例    if (isRenderWatcher) { // 渲染watcher      vm._watcher = this    }    vm._watchers.push(this)    // options    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 // //用户传入的回调函数 vm.$watch('msg',cb)    this.id = ++uid // watcher的唯一标识 每次产生一个watcher都要有一个唯一标识    this.active = true     this.dirty = this.lazy // for lazy watchers    this.deps = [] // 存 watcher 的依赖收集器    this.newDeps = [] // 存 dep 的    this.depIds = new Set()    this.newDepIds = new Set()    this.expression = process.env.NODE_ENV !== 'production'      ? expOrFn.toString()      : ''    // 判断传入的是表达式还是函数 赋值给 this.getter    if (typeof expOrFn === 'function') {      this.getter = expOrFn    } else {       this.getter = parsePath(expOrFn) // 用parsePath 读取一个字符串的 keyPath    }    // 对于渲染watcher 会立马执行 this.get()进行页面渲染    this.value = this.lazy      ? undefined      : this.get()  }  /**   * 让getter执行,从实例上取值渲染页面 就会调用Object.defineProperty 的get方法,就会走依赖收集的过程   * this.getter 是实例化 watcher 时传递的第二个参数,一个函数或者字符串,比如:updateComponent 或者 parsePath 返回的读取 this.xx 属性值的函数   */  get () {    // 将 Dep.target 属性指向自己    pushTarget(this)  // Dep.target = target    // value 为回调函数执行的结果 比如执行 updateComponent,进入 patch 阶段    let value = this.getter.call(vm, vm)    const vm = this.vm      // popTarget()      // 这里清空了Dep.target,为了防止notify触发时,不停的绑定Watcher与Dep,      // 造成代码死循环      Dep.target = null;      this.cleanupDeps()      return value  }  /** 两件事:   *   1、添加 dep 给自己(watcher)   *   2、添加自己(watcher)到 dep   */  addDep (dep) {    // 判重,如果 dep 已经存在则不重复添加    const id = dep.id    if (!this.newDepIds.has(id)) {      // 缓存 dep.id,用于判重      this.newDepIds.add(id)      // 将 dep 存入 watcher      this.newDeps.push(dep)        // 避免在 dep 中重复添加 watcher      if (!this.depIds.has(id)) {        // 将watcher 存入 dep        dep.addSub(this)       }    }  }  /**   * Clean up for dependency collection.   */  cleanupDeps () {    let i = this.deps.length    while (i--) {      const dep = this.deps[i]      if (!this.newDepIds.has(dep.id)) {        dep.removeSub(this)      }    }    let tmp = this.depIds    this.depIds = this.newDepIds    this.newDepIds = tmp    this.newDepIds.clear()    tmp = this.deps    this.deps = this.newDeps    this.newDeps = tmp    this.newDeps.length = 0  }  /**   * 更新方法   * 根据 watcher 配置项,决定接下来怎么走,一般是 queueWatcher   */  update () {    /* istanbul ignore else */    if (this.lazy) {      // 懒执行时走这里,比如 computed      // 将 dirty 置为 true,可以让 computedGetter 执行时重新计算 computed 回调函数的执行结果      this.dirty = true    } else if (this.sync) {      // 同步执行,在使用 vm.$watch 或者 watch 选项时可以传一个 sync 选项,      // 当为 true 时在数据更新时该 watcher 就不走异步更新队列,直接执行 this.run       // 方法进行更新      this.run()    } else {      // 更新时一般都这里,将 watcher 放入 watcher 队列      queueWatcher(this)    }  }  /**   * 由 刷新队列函数 flushSchedulerQueue 调用,完成如下几件事:   *   1、执行实例化 watcher 传递的第二个参数,updateComponent 或者 获取 this.xx 的一个函数(parsePath 返回的函数)   *   2、更新旧值为新值   *   3、执行实例化 watcher 时传递的第三个参数,比如用户 watcher 的回调函数   */   run () {    if (this.active) {      // 调用 this.get 方法      const value = this.get()      if (        value !== this.value ||        isObject(value) ||        this.deep      ) {        // 更新旧值为新值        const oldValue = this.value        this.value = value        if (this.user) {          // 如果是用户 watcher,则执行用户传递的第三个参数 —— 回调函数,参数为 val 和 oldVal          try {            this.cb.call(this.vm, value, oldValue)          } catch (e) {            handleError(e, this.vm, `callback for watcher "${this.expression}"`)          }        } else {          // 渲染 watcher,this.cb = noop,一个空函数          this.cb.call(this.vm, value, oldValue)        }      }    }  }  /**   * Evaluate the value of the watcher.   * This only gets called for lazy watchers.   */  evaluate () {    this.value = this.get()    this.dirty = false  }  /**   * 依赖于这个观察者收集的所有 deps.   */  depend () {    let i = this.deps.length    while (i--) {      this.deps[i].depend()    }  }  /**   * Remove self from all dependencies' subscriber list.   */  teardown () {    if (this.active) {      // remove self from vm's watcher list      // this is a somewhat expensive operation so we skip it      // if the vm is being destroyed.      if (!this.vm._isBeingDestroyed) {        remove(this.vm._watchers, this)      }      let i = this.deps.length      while (i--) {        this.deps[i].removeSub(this)      }      this.active = false    }  }}
依赖收集器Dep
/* @flow */import type Watcher from './watcher'import { remove } from '../util/index'import config from '../config'let uid = 0/** * 一个 dep 对应一个 obj.key [] * 在读取响应式数据时,负责收集依赖,每个 dep(或者说 obj.key)依赖的 watcher 有哪些 * 在响应式数据更新时,负责通知 dep 中那些 watcher 去执行 update 方法 */export default class Dep {  constructor () {    this.id = uid++    this.subs = []  }  addSub (sub) { // sub: Watcher    this.subs.push(sub)  }  removeSub (sub) { // sub: Watcher    remove(this.subs, sub)  }  // 向 watcher 中添加 dep  depend () {    if (Dep.target) {      Dep.target.addDep(this)    }  }  /**   * 通知 dep 中的所有 watcher,   * 执行 watcher.update() 方法   */  notify () {    const subs = this.subs.slice() // 返回一个新数组    // 遍历 dep 中存储的 watcher,执行 watcher.update()    for (let i = 0, l = subs.length; i < l; i++) {      subs[i].update()    }  }}Dep.target = nullconst targetStack = []// 设置 Dep.target = watcheexport function pushTarget (target) {  targetStack.push(target)  Dep.target = target}// 依赖收集结束调用,设置 Dep.target = nullexport function popTarget () {  targetStack.pop()  Dep.target = targetStack[targetStack.length - 1]}