我们之前提到过 Vue.js 构建过程,在 web 应⽤下,我们来分析 Runtime + Compiler 构建出来的 Vue.js, 它的⼊⼝是 src/platforms/web/entry-runtime-with-compiler.js :
Vue 的⼊⼝ 在这个⼊⼝ JS 的上⽅我们可以找到 Vue 的来源: import Vue from './runtime/index' ,我们先 来看⼀下这块⼉的实现,它定义在 src/platforms/web/runtime/index.js 中:
这⾥有 2 处关键的代码, import Vue from './instance/index' 和 initGlobalAPI(Vue) ,初始 化全局 Vue API(我们稍后介绍),我们先来看第⼀部分,在 src/core/instance/index.js 中:
Vue 的定义
import { stateMixin } from './state' import { renderMixin } from './render' import { eventsMixin } from './events'
import { lifecycleMixin } from './lifecycle' import { warn } from '../util/index'
function Vue (options) {
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)
}
initMixin(Vue) stateMixin(Vue) eventsMixin(Vue) lifecycleMixin(Vue) renderMixin(Vue)
export default Vue
在这⾥,我们终于看到了 Vue 的庐⼭真⾯⽬,它实际上就是⼀个⽤ Function 实现的类,我们只能通过
new Vue 去实例化它。
有些同学看到这不禁想问,为何 Vue 不⽤ ES6 的 Class 去实现呢?我们往后看这⾥有很多 xxxMixin 的函数调⽤,并把 Vue 当参数传⼊,它们的功能都是给 Vue 的 prototype 上扩展⼀些⽅法(这⾥具体的细节会在之后的⽂章介绍,这⾥不展开),Vue 按功能把这些扩展分散到多个模块中去实现,⽽不是在⼀个模块⾥实现所有,这种⽅式是⽤ Class 难以实现的。这么做的好处是⾮常⽅便代码的维护和管理,这种编程技巧也⾮常值得我们去学习。
initGlobalAPI
Vue.js 在整个初始化过程中,除了给它的原型 prototype 上扩展⽅法,还会给 Vue 这个对象本⾝扩展全局的静态⽅法,它的定义在 src/core/global-api/index.js 中:
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)
这⾥就是在 Vue 上扩展的⼀些全局⽅法的定义,Vue 官⽹中关于全局 API 都可以在这⾥找到,这⾥不 会介绍细节,会在之后的章节我们具体介绍到某个 API 的时候会详细介绍。有⼀点要注意的 是, Vue.util 暴露的⽅法最好不要依赖,因为它可能经常会发⽣变化,是不稳定的。 总结 那么⾄此,Vue 的初始化过程基本介绍完毕。这⼀节的⽬的是让同学们对 Vue 是什么有⼀个直观的认 识,它本质上就是⼀个⽤ Function 实现的 Class,然后它的原型 prototype 以及它本⾝都扩展了⼀系列的 ⽅法和属性,那么 Vue 能做什么,它是怎么做的,我们会在后⾯的章节⼀层层帮⼤家揭开 Vue 的神秘