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

计算属性的初始化相对复杂一些,首先要对计算属性建立观察,然后再在实例上重新定义计算属性,并且执行属性代理。由于加入了服务器渲染的功能,在定义计算属性的时候对使用环境做判断,是非服务器渲染会影响到计算属性的定义,这是由于服务器渲染下使用框架时,计算属性是不提供 setter 的;另外也要根据用户定义的值是函数或者对象来对计算属性重新定义 getter 和 setter。从这段代码里可以看出一个非常重要的程序,即在获取计算属性的时候才去计算它的值,这正是懒加载的实现。

initMethods

// 定义initMethods方法,接受实例vm,配置属性methods
function initMethods (vm: Component, methods: Object) {
 // 获取实例的props
 const props = vm.$options.props
 // 遍历methods对象
 for (const key in methods) {
 // 非生产环境下给出警告
 if (process.env.NODE_ENV !== 'production') {
  // 未赋值方法警告
  if (methods[key] == null) {
  warn(
   `Method "${key}" has an undefined value in the component definition. ` +
   `Did you reference the function correctly?`,
   vm
  )
  }
  // 与props属性名冲突警告
  if (props && hasOwn(props, key)) {
  warn(
   `Method "${key}" has already been defined as a prop.`,
   vm
  )
  }
  // 与保留字冲突警告
  if ((key in vm) && isReserved(key)) {
  warn(
   `Method "${key}" conflicts with an existing Vue instance method. ` +
   `Avoid defining component methods that start with _ or $.`
  )
  }
 }
 // 在实例上定义方法,赋值为用户未定义函数或空函数
 vm[key] = methods[key] == null ? noop : bind(methods[key], vm)
 }
}

initMethods 函数非常简单,除了一大段在非生产环境里报告检查冲突的代码,唯一的内容就是在实例上定义相应的方法并且把上下文绑定到实例对象上,这样即便不是使用箭头函数,在方法内也默认用 this 指代了实例对象。

initWatch

// 定义initWatch函数,接受实例vm和配置属性watch
function initWatch (vm: Component, watch: Object) {
 // 遍历watch
 for (const key in watch) {
 // 暂存属性的值
 const handler = watch[key]
 // 如果handler是数组
 if (Array.isArray(handler)) {
  // 遍历数组为每一个元素创建相应watcher
  for (let i = 0; i < handler.length; i++) {
  createWatcher(vm, key, handler[i])
  }
 } else {
  // 窦否则handler应该是函数,直接为key创建watcher
  createWatcher(vm, key, handler)
 }
 }
}

// 定义createWatcher函数
// 接受实例vm、表达式或函数expOrFn,处理器handler,可选的options
function createWatcher (
 vm: Component,
 expOrFn: string | Function,
 handler: any,
 options?: Object
) {
 // 如果handler是对象
 if (isPlainObject(handler)) {
 // 将handler赋值给options.
 options = handler
 // 重新赋值handler
 handler = handler.handler
 }
 // 如果handler是字符串,在实例上寻找handler并赋值给handler
 if (typeof handler === 'string') {
 handler = vm[handler]
 }
 // 创建观察并返回
 return vm.$watch(expOrFn, handler, options)
}


      

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

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