话不多说先上源码:

export function initGlobalAPI (Vue: GlobalAPI) {  // config  const configDef = {}  configDef.get = () => config  if (process.env.NODE_ENV !== 'production') {    configDef.set = () => {      warn(        'Do not replace the Vue.config object, set individual fields instead.'      )    }  }  Object.defineProperty(Vue, 'config', configDef)  // exposed util methods.  // NOTE: these are not considered part of the public API - avoid relying on  // them unless you are aware of the risk.  Vue.util = {    warn,    extend,    mergeOptions,    defineReactive  }  Vue.set = set  Vue.delete = del  Vue.nextTick = nextTick  // 2.6 explicit observable API  Vue.observable = <T>(obj: T): T => {    observe(obj)    return obj  }  Vue.options = Object.create(null)  ASSET_TYPES.forEach(type => {    Vue.options[type + 's'] = Object.create(null)  })  // this is used to identify the "base" constructor to extend all plain-object  // components with in Weex's multi-instance scenarios.  Vue.options._base = Vue  extend(Vue.options.components, builtInComponents)  initUse(Vue)  initMixin(Vue)  initExtend(Vue)  initAssetRegisters(Vue)}

第一部分:

  // config  const configDef = {}  configDef.get = () => config  if (process.env.NODE_ENV !== 'production') {    configDef.set = () => {      warn(        'Do not replace the Vue.config object, set individual fields instead.'      )    }  }  Object.defineProperty(Vue, 'config', configDef)

这里劫持了Vueconfig属性,使的无法对其进行修改。


第二部分:

 Vue.util = {    warn,    extend,    mergeOptions,    defineReactive  }
  • 首先看 warn,它实际来自于 /src/core/util/debug.js
 warn = (msg, vm) => {    const trace = vm ? generateComponentTrace(vm) : ''    if (config.warnHandler) {      config.warnHandler.call(null, msg, vm, trace)    } else if (hasConsole && (!config.silent)) {      console.error(`[Vue warn]: ${msg}${trace}`)    }  }  tip = (msg, vm) => {    if (hasConsole && (!config.silent)) {      console.warn(`[Vue tip]: ${msg}` + (        vm ? generateComponentTrace(vm) : ''      ))    }  }

如果用过VuewarnHandler功能应该都知道,这是一个自定义警告处理函数,哈哈其实我没用过,但是动手去官网查了一下。

其实也就是我们可以通过自定义warnHandler函数做一些项目警告的收集,同样的功能还有errorHandler,如果有需要可以去官方文档看看。generateComponentTrace 方法会追踪到项目警告组件的踪迹,也就是一个定位功能。

如果没有定义warnHandler,在写组件不规范的情况下,就会在控制台打印错误,这应该非常常见了~

  • extend , 顺着找下去来自于 /share/utils
/** * Mix properties into target object. */export function extend (to: Object, _from: ?Object): Object {  for (const key in _from) {    to[key] = _from[key]  }  return to}

作用就是将源对象的属性混入到目标对象。

  • mergeOptions/core/util/options.js
export function mergeOptions (  parent: Object,  child: Object,  vm?: Component): Object {  if (process.env.NODE_ENV !== 'production') {    checkComponents(child)  }  if (typeof child === 'function') {    child = child.options  }  normalizeProps(child, vm)  normalizeInject(child, vm)  normalizeDirectives(child)  // Apply extends and mixins on the child options,  // but only if it is a raw options object that isn't  // the result of another mergeOptions call.  // Only merged options has the _base property.  if (!child._base) {    if (child.extends) {      parent = mergeOptions(parent, child.extends, vm)    }    if (child.mixins) {      for (let i = 0, l = child.mixins.length; i < l; i++) {        parent = mergeOptions(parent, child.mixins[i], vm)      }    }  }  const options = {}  let key  for (key in parent) {    mergeField(key)  }  for (key in child) {    if (!hasOwn(parent, key)) {      mergeField(key)    }  }  function mergeField (key) {    const strat = strats[key] || defaultStrat    options[key] = strat(parent[key], child[key], vm, key)  }  return options}

作用是将父子的策略项合并为一个
checkComponents 就是检查组件,内部遍历了传入的childcomponents属性检查组件名字是否规范。
normalizeProps 其作用就是统一将props: [?]props: {?}形式转换为后者的形式。
normalizeInject 也是统一标准化传入的injectinject一般是父组件或者祖父组件 provide的值,也是一种通信方式。
normalizeDirectives标准化自定义指令,如果传入的是个function, 会被定义成{ bind: function, update: function}这种形式。
下面还有如果子组件有 extends或者mixins将会改变父组件等功能,等遇到具体调用的时候再分析。
mergeField 这个是实际做的事情,它会按照strats定义的的策略进行合并。

strats.el = strats.propsData = function (parent, child, vm, key) {strats.data = function () {...}strats.props = ...strats.methods = ...strats.computed = ...strats.watch = ......
  • defineReactive/core/observer/index.js 下,是Vue 实现响应式的关键,后续会详细再说,这里相当于给util赋予了这个功能。
  • setdel 作用就是响应式的添加或删除属性
  • nextTick 可以在下次 DOM 更新循环结束之后执行延迟回调。与JS的事件运行机制非常像,会单独记录一篇文章。
  • Vue.observable 这个是 Vue 2.6版本新增的API,很明显的看到了它使用了VueObserve,它的作用就是,假如一个小型的项目根本用不上Vuex进行状态管理,那么就可以使用它自定义一个小型的响应式store供全局使用,详情可以参照官方文档。
  • Vue.options
// 遍历了ASSET_TYPES初始化Vue.options  Vue.options = Object.create(null)  ASSET_TYPES.forEach(type => {    Vue.options[type + 's'] = Object.create(null)  })// 下面是ASSET_TYPES的定义  export const ASSET_TYPES = [    'component',    'directive',    'filter'  ]
  • extend(Vue.options.components, builtInComponents)builtInCompoents属性混入Vue.options.components,里面是一些keep-alive相关的东西。
  • initUse(Vue) 如下:
export function initUse (Vue: GlobalAPI) {  Vue.use = function (plugin: Function | Object) {    const installedPlugins = (this._installedPlugins || (this._installedPlugins = []))    if (installedPlugins.indexOf(plugin) > -1) {      return this    }    // additional parameters    const args = toArray(arguments, 1)    args.unshift(this)    if (typeof plugin.install === 'function') {      plugin.install.apply(plugin, args)    } else if (typeof plugin === 'function') {      plugin.apply(null, args)    }    installedPlugins.push(plugin)    return this  }}

Vue上添加了use,接收一个插件参数,安装插件。平时我们注册类似router等插件的时候,就会用到Vue.use(router)。其内部维护了一个_installedPlugins数组用来存储所有安装的插件,安装时会判断插件是否实现了install方法,如果有就会执行插件的install方法,在这里Vue巧妙的将自己注入到install方法的参数中,这样的好处就是,在实现install方法就不需要import Vue了。

  • initMixin
export function initMixin (Vue: GlobalAPI) {  Vue.mixin = function (mixin: Object) {    this.options = mergeOptions(this.options, mixin)    return this  }}

全局混入,将mixin通过合并策略混入全局的options,一旦使用全局混入,由于局部注册组件,其实是调用了Vue.extend方法,其调用时也会进行mergeOptions,所以会影响每一个之后创建的 Vue 实例。应当恰当使用。

  • initExtend
export function initExtend (Vue: GlobalAPI) {  /**   * Each instance constructor, including Vue, has a unique   * cid. This enables us to create wrapped "child   * constructors" for prototypal inheritance and cache them.   */  Vue.cid = 0  let cid = 1  /**   * Class inheritance   */  Vue.extend = function (extendOptions: Object): Function {    extendOptions = extendOptions || {}    const Super = this    const SuperId = Super.cid    const cachedCtors = extendOptions._Ctor || (extendOptions._Ctor = {})    if (cachedCtors[SuperId]) {      return cachedCtors[SuperId]    }    const name = extendOptions.name || Super.options.name    if (process.env.NODE_ENV !== 'production' && name) {      validateComponentName(name)    }    const Sub = function VueComponent (options) {      this._init(options)    }    Sub.prototype = Object.create(Super.prototype)    Sub.prototype.constructor = Sub    Sub.cid = cid++    Sub.options = mergeOptions(      Super.options,      extendOptions    )    Sub['super'] = Super    // For props and computed properties, we define the proxy getters on    // the Vue instances at extension time, on the extended prototype. This    // avoids Object.defineProperty calls for each instance created.    if (Sub.options.props) {      initProps(Sub)    }    if (Sub.options.computed) {      initComputed(Sub)    }    // allow further extension/mixin/plugin usage    Sub.extend = Super.extend    Sub.mixin = Super.mixin    Sub.use = Super.use    // create asset registers, so extended classes    // can have their private assets too.    ASSET_TYPES.forEach(function (type) {      Sub[type] = Super[type]    })    // enable recursive self-lookup    if (name) {      Sub.options.components[name] = Sub    }    // keep a reference to the super options at extension time.    // later at instantiation we can check if Super's options have    // been updated.    Sub.superOptions = Super.options    Sub.extendOptions = extendOptions    Sub.sealedOptions = extend({}, Sub.options)    // cache constructor    cachedCtors[SuperId] = Sub    return Sub  }}

这里实现了一个js的经典继承,此方法用于创建Vue的子类构造函数。在这里就可以验证了上面说的,调用时会将Super.optionsextendOptions合并。

  • initAssetRegisters
export function initAssetRegisters (Vue: GlobalAPI) {  /**   * Create asset registration methods.   */  ASSET_TYPES.forEach(type => {    Vue[type] = function (      id: string,      definition: Function | Object    ): Function | Object | void {      if (!definition) {        return this.options[type + 's'][id]      } else {        /* istanbul ignore if */        if (process.env.NODE_ENV !== 'production' && type === 'component') {          validateComponentName(id)        }        if (type === 'component' && isPlainObject(definition)) {          definition.name = definition.name || id          definition = this.options._base.extend(definition)        }        if (type === 'directive' && typeof definition === 'function') {          definition = { bind: definition, update: definition }        }        this.options[type + 's'][id] = definition        return definition      }    }  })}

ASSET_TYPES在上面已经提到过了,这里是初始化Vue的注册器,比如我们要注册组建的时候会调用Vue.component,要自定义指令时会使用Vue.directive,就是在这定义的。

总结

这里主要讲的就是Vue官网全局API的内容,不算特别详细,但也一一介绍到了,如果要追求更深入的了解,可以去git上下载一份源码钻研钻研,其实在继承那里,类似initPropsinitComputed 也是能提升项目中对Vue用法的理解。