咱們以前提到過 Vue.js 構建過程,在 web 應用下,咱們來分析 Runtime + Compiler 構建出來的 Vue.js,它的入口是 src/platforms/web/entry-runtime-with-compiler.js:ios
摘選entry-runtime-with-compiler.jsweb
import config from 'core/config' import { warn, cached } from 'core/util/index' import { mark, measure } from 'core/util/perf' //主角在這裏 import Vue from './runtime/index' import { query } from './util/index' import { compileToFunctions } from './compiler/index' import { shouldDecodeNewlines, shouldDecodeNewlinesForHref } from './util/compat'
在這個入口 JS 的上方咱們能夠找到 Vue 的來源:import Vue from './runtime/index',咱們先來看一下這塊兒的實現,它定義在 src/platforms/web/runtime/index.js 中:編程
import Vue from 'core/index' import config from 'core/config' import { extend, noop } from 'shared/util'
這裏關鍵的代碼是 import Vue from 'core/index'是真正初始化 Vue 的地方[/src/core/index.js]api
import Vue from './instance/index' import { initGlobalAPI } from './global-api/index'
這裏有 2 處關鍵的代碼,import Vue from './instance/index'(./指的是當前目錄) 和 initGlobalAPI(Vue),初始化全局 Vue API,咱們先來看第一部分,在 src/core/instance/index.js 中:less
import { initMixin } from './init' 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
1ide
在這裏,咱們終於看到了 Vue 的廬山真面目,它實際上就是一個用 Function 實現的類,咱們只能經過 new Vue 去實例化它函數
爲什麼 Vue 不用 ES6 的 Class 去實現呢?咱們日後看這裏有不少 xxxMixin 的函數調用,並把 Vue 當參數傳入,它們的功能都是給 Vue 的 prototype 上擴展一些方法(這裏具體的細節會在以後的文章介紹,這裏不展開),Vue 按功能把這些擴展分散到多個模塊中去實現,而不是在一個模塊裏實現全部,這種方式是用 Class 難以實現的。這麼作的好處是很是方便代碼的維護和管理,這種編程技巧也很是值得咱們去學習。oop
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) // 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 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) }
這裏就是在 Vue 上擴展的一些全局方法的定義,Vue 官網中關於全局 API 均可以在這裏找到,這裏不會介紹細節,會在以後的章節咱們具體介紹到某個 API 的時候會詳細介紹。有一點要注意的是,Vue.util 暴露的方法最好不要依賴,由於它可能常常會發生變化,是不穩定的。ui