认识Vue构造函数

110 阅读1分钟

总结

这部分就是介绍Vue构造函数有什么方法和属性。没什么意思,直接给总结。

  1. src/core/instance/index.js初始化Vue的原型(Vue.prototype)
  2. src/core/index.js初始化Vue的全局方法和属性
  3. src/platforms/web/runtime/index.js初始化平台相关的配置,patch方法和$mount
  4. web/entry-runtime-with-compiler.js重写$mount使其拥有编译的能力

浏览器打印原型

Vue.prototype.png

浏览器打印全局方法和属性

Vue.png

起源

找到Vue构造函数相关的文件(怎么找?不再赘述)如下:

  1. web/entry-runtime-with-compiler.js
  2. src/platforms/web/runtime/index.js
  3. src/core/index.js
  4. src/core/instance/index.js

通过层层引用,最终找到真正定义Vue的地方src/core/instance/index.js。其实Vue的构造函数核心就是调用_init方法。new Vue实际上就是执行_init方法。

function Vue (options) {
    // 必须使用new关键字来生产Vue实例
  if (process.env.NODE_ENV !== 'production' &&
    !(this instanceof Vue)
  ) {
    warn('Vue is a constructor and should be called with the `new` keyword')
  }
  this._init(options)
}
// 向Vue的原型上添加_init方法
initMixin(Vue)
// 向Vue的原型上添加 $set, $watch, $delete方法
// 并将_data和_props代理到实例上
stateMixin(Vue)
// 初始化事件模型, 发布订阅者模式
eventsMixin(Vue)
// 向vue原型上添加_update, $forceUpdate, $destory
lifecycleMixin(Vue)
// 向Vue原型上添加$nextTick,_render方法和一系列的render帮助函数
renderMixin(Vue)

src/core/instance/index.js中执行的方法,都是为Vue.prototype添加一些方法。其中就有常用的$set,$emit,$nextTick...

Vue.protoType = {
    // initMixin
    _init: function,
    // stateMixin
    $set: set,
    $delete: del,
    $watch: function,
    $data: get(_data),
    $prop: get(_props),
    // eventsMixin
    $on: function,
    $once: function,
    $off: function,
    $emit: function,
    // lifecyycleMixin
    _update: function,
    $forceUpdate: function,
    $destory: function,
    // renderMiXin
    $nextTick: function,
    _render: function,
    // installRenderHelpers
    // 帮助生成render函数的方法
    _o: function,
    _n: function,
    _s: function,
    _l: function,
    _t: function,
    _q: function,
    _i: function,
    _m: function,
    _f: function,
    _k: function,
    _b: function,
    _v: function,
    _e: function,
    _u: function,
    _g: function,
    _d: function,
    _p : function,
}

之后,被src/core/index.js引用,并执initGlobalAPI,为Vue添加静态方法和初始化配置。

// 初始化全局方法
initGlobalAPI(Vue)
// 会被替换为package.json中的版本号
Vue.version = '__VERSION__'
// src/core/global-api/index.js
export function initGlobalAPI (Vue: GlobalAPI) {
  // config
  const configDef = {}
  configDef.get = () => config
  // 定义config属性
  Object.defineProperty(Vue, 'config', configDef)
  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)
  })
  Vue.options._base = Vue
// 添加内置组件keep-alive
  extend(Vue.options.components, builtInComponents)
  // 初始化use方法
  initUse(Vue)
  // 初始化mixin
  initMixin(Vue)
  // 初始化extend,cid
  initExtend(Vue)
  initAssetRegisters(Vue)
}

其中,options._base存储就是Vue构造函数,组件最后都会继承Vue构造函数,意思就是所有的组件options._base都是Vue

{
    config: {
      optionMergeStrategies: Object.create(null),
      silent: false,
      productionTip: process.env.NODE_ENV !== 'production',
      devtools: process.env.NODE_ENV !== 'production',
      performance: false,
      errorHandler: null,
      warnHandler: null,nore certain custom elements
      ignoredElements: [],
      keyCodes: Object.create(null),
      isReservedTag: no,
      isReservedAttr: no,
      isUnknownElement: no,
      getTagNamespace: noop,
      parsePlatformTagName: identity,
      mustUseProp: no,
      async: true,
      _lifecycleHooks: LIFECYCLE_HOOKS
    },
    // util暴露的方法不建议使用
    util:{
      warn,
      extend,
      mergeOptions,
      defineReactive
    },
    set: set,
    delete: del,
    nextTick: nextTick,
    observable: function,
    // 基础配置
    options: {
        components: {
            KeepAlive
        },
        directives: {},
        filters: {},
        _base: Vue
    },
    use: funtion,
    // 全局mixin
    mixin: funtion,
    // 全局extend
    cid: 0,
    extend: function,  
   // 全局组件,filter,指令注册
    compnent: function,
    filter: function,
    directive: function,
}

Vue添加静态方法之后,又被src/platforms/web/runtime/index.js引用,为Vue添加平台所需要的方法,以下web平台相关的,以下:

// install platform specific utils
Vue.config.mustUseProp = mustUseProp
// 是否保留标签,html和svg标签
Vue.config.isReservedTag = isReservedTag
// 是否style,class属性
Vue.config.isReservedAttr = isReservedAttr
// 获取svg,math命名空间
Vue.config.getTagNamespace = getTagNamespace
// 判断是否合法的html标签
Vue.config.isUnknownElement = isUnknownElement
// install platform runtime directives & components
// 混合model和show指令
extend(Vue.options.directives, platformDirectives)
// 混合transition,TransitionGroup内置组件
extend(Vue.options.components, platformComponents)
// install platform patch function
Vue.prototype.__patch__ = inBrowser ? patch : noop
// public mount method
Vue.prototype.$mount = function (
  el?: string | Element,
  hydrating?: boolean
): Component {}

Vue.config添加了web环境下具体的实现,添加了v-modev-show指令,添加了transitionTransitionGroup内置组件,向Vue.prototype添加了__patch__$mount方法。

接下来就到了最后一步,打开web/entry-runtime-with-compiler.js,这里就不贴相关代码,就是重写$mount方法,使其拥有编译的能力。也就是平时用于开发的版本,可以将写的模板编译成render函数。开发环境中,Vue首先会把我们写的单文件组件编译成render函数,然后再进行挂载。