methods处理

在分析完props相关逻辑后,我们接下来分析与methods相关的逻辑,这部分相比于props要简单得多。

export function initState (vm: Component) {
  // 省略代码
  const opts = vm.$options
  if (opts.methods) initMethods(vm, opts.methods)
}

initState()方法中,调用了initMethods()并传入了当前实例vm和我们撰写的methods。接下来,我们看一下initMethods方法具体的实现:

function initMethods (vm: Component, methods: Object) {
  const props = vm.$options.props
  for (const key in methods) {
    if (process.env.NODE_ENV !== 'production') {
      if (typeof methods[key] !== 'function') {
        warn(
          `Method "${key}" has type "${typeof methods[key]}" in the component definition. ` +
          `Did you reference the function correctly?`,
          vm
        )
      }
      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] = typeof methods[key] !== 'function' ? noop : bind(methods[key], vm)
  }
}

在以上代码中可以看到,initMethods()方法实现中最重要的一段代码就是:

// 空函数
function noop () {}

vm[key] = typeof methods[key] !== 'function' ? noop : bind(methods[key], vm)

它首先判断了我们定义的methods是不是function类型,如果不是则赋值为一个noop空函数,如果是则把这个方法进行bind绑定,其中传入的vm为当前实例。这样做的目的是为了把methods方法中的this指向当前实例,使得我们能在methods方法中通过this.xxx的形式,很方便的访问到propsdata以及computed等与实例相关的属性或方法。

在开发环境下,它还做了如下几种判断:

  • 必须为function类型。
// 抛出错误:Method sayHello has type null in the component definition. 
//          Did you reference the function correctly?
export default {
  methods: {
    sayHello: null
  }
}
  • 命名不能和props冲突。
// 抛出错误:Method name has already been defined as a prop.
export default {
  props: ['name']
  methods: {
    name () {
      console.log('name')
    }
  }
}
  • 命名不能和已有的实例方法冲突。
// 抛出错误:Method $set conflicts with an existing Vue instance method. 
//          Avoid defining component methods that start with _ or $.
export default {
  methods: {
    $set () {
      console.log('$set')
    }
  }
}

在分析完以上initMethods流程后,我们能得到如下流程图:

最后更新时间:
贡献者: wangtunan