Vue源码探究之状态初始化(4)

与 props 的处理类似,initData 函数的作用也是为了对数据建立观察的依赖关系,并且代理数据到私有变量 _data 上,另外包括了对 data 与其他配置对象属性的键名冲突的检测。

initComputed

// 设置computedWatcherOptions对象
const computedWatcherOptions = { computed: true }

// 定义initComputed函数,接受实例vm,和computed对象
function initComputed (vm: Component, computed: Object) {
 // $flow-disable-line
 // 定义watchers和实例_computedWatchers属性,初始赋值空对象
 const watchers = vm._computedWatchers = Object.create(null)
 // 是否是服务器渲染,computed属性在服务器渲染期间只能是getter
 // computed properties are just getters during SSR
 const isSSR = isServerRendering()

 // 遍历computed
 for (const key in computed) {
 // 获取用户定义的值
 const userDef = computed[key]
 // 如果用户定义的是函数则赋值给getter否则j将userDef.get方法赋值给getter
 const getter = typeof userDef === 'function' ? userDef : userDef.get
 // 非生产环境抛出缺少计算属性错误警告
 if (process.env.NODE_ENV !== 'production' && getter == null) {
  warn(
  `Getter is missing for computed property "${key}".`,
  vm
  )
 }

 // 非服务器渲染下
 if (!isSSR) {
  // 为计算属性创建内部监视器
  // create internal watcher for the computed property.
  watchers[key] = new Watcher(
  vm,
  getter || noop,
  noop,
  computedWatcherOptions
  )
 }

 // 组件定义的内部计算属性已经在组件的原型上定义好了
 // 所以这里只要关注实例初始化时用户定义的计算属性
 // component-defined computed properties are already defined on the
 // component prototype. We only need to define computed properties defined
 // at instantiation here.
 // 键名非实例根属性时,定义计算属性,具体参照defineComputed函数
 if (!(key in vm)) {
  defineComputed(vm, key, userDef)
 // 非生产环境下,检测与data属性名的冲突并给出警告
 } 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)
  }
 }
 }
}

// 定义并导出defineComputed哈数
// 接收实例target,计算属性键名key,计算属性值userDef参数
export function defineComputed (
 target: any,
 key: string,
 userDef: Object | Function
) {
 // 在非服务器渲染下设置缓存
 const shouldCache = !isServerRendering()
 // 计算属性值是函数时
 if (typeof userDef === 'function') {
 // 设置计算属性的getter,setter为空函数
 sharedPropertyDefinition.get = shouldCache
  ? createComputedGetter(key)
  : userDef
 sharedPropertyDefinition.set = noop
 } else {
 // 当计算属性是对象时,设置计算属性的getter和setter
 sharedPropertyDefinition.get = userDef.get
  ? shouldCache && userDef.cache !== false
  ? createComputedGetter(key)
  : userDef.get
  : noop
 sharedPropertyDefinition.set = userDef.set
  ? userDef.set
  : noop
 }
 // 非生产环境下,如果没哟定义计算属性的setter
 // 想设置计算属性时给出警告
 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
  )
 }
 }
 // 以重新设置的属性描述符为基础在实例对象上定义计算属性
 Object.defineProperty(target, key, sharedPropertyDefinition)
}

// 定义createComputedGetter,创建计算属性getter
// 目的是在非服务器渲染情况下建立计算属性的观察依赖,
// 并根据其依赖属性返回计算后的值
function createComputedGetter (key) {
 return function computedGetter () {
 const watcher = this._computedWatchers && this._computedWatchers[key]
 if (watcher) {
  watcher.depend()
  return watcher.evaluate()
 }
 }
}


      

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/428.html