1.首先从computed钻研开始

function initComputed (vm: Component, computed: Object) {  // 首先应用连等形式,申明watchers,并给vue实例上增加_computedWatchers属性,二者指向同一对象,用来记录所有的computed  const watchers = vm._computedWatchers = Object.create(null)  // 判断是否是服务端渲染  const isSSR = isServerRendering()  for (const key in computed) {    const userDef = computed[key]    // computed两种申明形式函数、对象:{get,set}    const getter = typeof userDef === 'function' ? userDef : userDef.get    if (!isSSR) {      // create internal watcher for the computed property.      // 给每一个computed创立Watcher实例,并增加到watchers,vm._computedWatchers也会增加      watchers[key] = new Watcher(        vm,        getter || noop,        noop,        computedWatcherOptions      )    }    // 判断vm上是否已存在雷同属性名,存在报错,不存在代理到vm上,以便this.xxx调用    if (!(key in vm)) {      defineComputed(vm, key, userDef)    } else if (process.env.NODE_ENV !== 'production') {      if (key in vm.$data) {        warn(`The computed property "${key}" is already defined in data.`, vm)      } else if (vm.$options.props && key in vm.$options.props) {        warn(`The computed property "${key}" is already defined as a prop.`, vm)      } else if (vm.$options.methods && key in vm.$options.methods) {        warn(`The computed property "${key}" is already defined as a method.`, vm)      }    }  }}

2.defineComputed
1) 首先看下noop函数是什么?

// noop就是一个空函数export function noop (a?: any, b?: any, c?: any) {}

2) 看一下createComputedGetter函数

function createComputedGetter (key) {  // 例: computedName(){return '我的名字是' + this.name}  // 返回一个getter函数,将computed属性(computedName)的get指向到watcher.value,  // 这里的watcher.value会触发watcher.prototype.get办法,进而触发computed中依赖响应式变量的get办法,  // 而后触发dep.depend(),将watcher增加到该变量闭包中dep实例的subs数组  return function computedGetter () {    const watcher = this._computedWatchers && this._computedWatchers[key]    if (watcher) {      // computed的默认会传lazy:true, watcher.dirty初始值等于lazy,所以这里是true      if (watcher.dirty) {        //this.value 获取值,并且把dirty设置为false,这样就能够起到缓存的作用,屡次拜访同一个computed,只会触发一次watcher.get()        // evaluate () {        //   this.value = this.get()        //   this.dirty = false        // }        watcher.evaluate() // 翻译是估值,求函数的值      }      if (Dep.target) {        watcher.depend()      }      return watcher.value    }  }}

3) 最初看一下最终的defineComputed函数,这里会用到noop和createComputedGetter,所以在下面提前理解一下

// 例: computedName(){return '我的名字是' + this.name}export function defineComputed (  target: any,  key: string,  userDef: Object | Function) {  // 判断是否是服务端渲染,这里只钻研客户端渲染的状况  const shouldCache = !isServerRendering()  if (typeof userDef === 'function') {    // 客户端渲染时shouldCache为true,也就是会将computedName.get设置为createComputedGetter(),    // createComputedGetter会返回一个getter办法,见下方    sharedPropertyDefinition.get = shouldCache      ? createComputedGetter(key)      : createGetterInvoker(userDef)    sharedPropertyDefinition.set = noop  } else {    sharedPropertyDefinition.get = userDef.get      ? shouldCache && userDef.cache !== false        ? createComputedGetter(key)        : createGetterInvoker(userDef.get)      : noop    sharedPropertyDefinition.set = userDef.set || noop  }  // 如果computed属性是function时,被设置时会报错,这就是咱们平时为什么computed不能被设置的起因  if (process.env.NODE_ENV !== 'production' &&      sharedPropertyDefinition.set === noop) {    sharedPropertyDefinition.set = function () {      warn(        `Computed property "${key}" was assigned to but it has no setter.`,        this      )    }  }  // 将computed属性(computedName)定义到vm上,这里的target就是vm(vue实例)  Object.defineProperty(target, key, sharedPropertyDefinition)}