Vue源码学习二 是对Vue的原型对象的包装,最后从Vue的出生文件导出了 Vue这个构造函数
来到 src/core/index.js
代码是:
import Vue from './instance/index' import { initGlobalAPI } from './global-api/index' import { isServerRendering } from 'core/shared/env' import { FunctionalRenderContext } from 'core/vdom/create-functional-component' // 将 Vue 构造函数作为参数, 传递给 initGlobalAPI 方法 // 向Vue.prototype 上添加一些静态属性和方法 initGlobalAPI(Vue) Object.defineProperty(Vue.prototype, '$isServer', { get: isServerRendering }) Object.defineProperty(Vue.prototype, '$ssrContext', { get () { /* istanbul ignore next */ return this.$vnode && this.$vnode.ssrContext } }) // expose FunctionalRenderContext for ssr runtime helper installation Object.defineProperty(Vue, 'FunctionalRenderContext', { value: FunctionalRenderContext }) Vue.version = '__VERSION__' // http://hcysun.me/vue-design/art/2vue-constructor.html#with-compiler export default Vue
看第一句 import Vue from './instance/index'
, 导入了Vue这个构造函数,且原型在上面已经添加了一些属性和方法。
然后 initGlobalAPI(Vue)
执行 initGlobalAPI 方法并且将 Vue构造函数就为参数调用。
$isServer、$ssrContext
。并且再 Vue构造函数上定义了 FunctionalRenderContext
静态属性,之所以在 Vue构造函数上定义,是因为在 ssr的时候要使用它。最后 Vue.version = '__VERSION__'
又在 Vue构造函数上定义了version,即版本号。 然后再看 initGlobalAPI
方法的来源地, 它主要是丰富 Vue构造函数,在构造函数上添加静态属性和方法。import { initGlobalAPI } from './global-api/index'。 来到 ./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.' ) } } // Vue构造函数上添加config属性, 也是只读的属性。 // Vue.config 代理的是从../config文件导出的对象 Object.defineProperty(Vue, 'config', configDef)
首先是这样的一段代码, 这段代码是在 Vue构造函数上添加 config
属性, 他也是一个只读的属性,和 $data
、$prop
是一样的。当你试图修改这个属性时,在非生产环境下会给你提醒warn
。
import config from '../config'
。 所以 Vue.config 代理的是从 core/config
导入的config对象。 然后是这样一段代码:
// exposed shared 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原型上添加了一个 util属性,它是一个对象。这个对象有四个属性 warn、extend、mergeOptions、defineReactive
。他们都是来自于 src/core/util/index
文件中。官网上没有这些api的说明, 也不推荐使用。
然后是一段这样的代码:
Vue.set = set Vue.delete = del Vue.nextTick = nextTick // options 通过Object.create()创建的一个空对象 Vue.options = Object.create(null)
上面这段代码是在 Vue构造函数上又添加了四个属性 set、delete、nextTick
和 options
。options
是通过 Object.create(null)
创建的一个空对象。下面的代码即丰富了 options
这个对象。
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
ASSET_TYPES
是上面呢?很明显他是一个数组,遍历它的每一个属性 + s 并且添加到 Vue.options上。并且初始赋值的都是 Object.create(null)
。看一下 ASSET_TYPES
来自src/shared/constants.js
文件。
export const ASSET_TYPES = [ 'component', 'directive', 'filter']
可以看到 ASSET_TYPES
是这么一个数组。原来是通过遍历向 Vue.options中添加 components、directives、filters
。
到目前,Vue.options现在是这样样子:
Vue.options = { components: Object.create(null), directives: Object.create(null), filters: Object.create(null), _base: Vue}
然后继续向下看是这样的一句代码
extend(Vue.options.components, builtInComponents)
extend
是 Vue的一个工具方法,在 src/shared/util.js
文件中
/** * Mix properties into target object. */export function extend (to: Object, _from: ?Object): Object { for (const key in _from) { to[key] = _from[key] } return to}
主要作用是将一个对象的属性混入到另外一个对象中。
那么上面的extend(Vue.options.components, builtInComponents)
的意思就是将 builtInComponents
对象的属性混入到 Vue.options.components
对象中。那么builtInComponents
对象是啥呢? 来到 src/core/components/indes.js
文件中: import KeepAlive from './keep-alive'export default { KeepAlive}
就是将 KeepAlive
这个属性添加到 Vue.options.conponents
中。
那么到目前为止, Vue.options对象已经变成了这个样子
Vue.options = { components: { KeepAlive }, directives: Object.create(null), filters: Object.create(null), _base: Vue}
再看这个文件的最后一部分代码
initUse(Vue) initMixin(Vue) initExtend(Vue) initAssetRegisters(Vue)
依此调用了四个方法,都是将 Vue这个构造函数作为其参数。initUse、initMixin、initExtend、initAssetRegisters
四个方法分别来自 ./global-api/use.js
、./global-api/mixin.js
、./global-api/extend.js
、./global-api/assets.js
文件。
先看 initUse
文件:
// 全局的 Vue.use() 用来安装插件的方法export function initUse (Vue: GlobalAPI) { Vue.use = function(){}}
该方法的主要作用是在 Vue上添加 use方法,也就是用来安装 Vue插件的全局API Vue.use()
。
initMixin
文件
// 在Vue上添加mixin的全局APIexport function initMixin (Vue: GlobalAPI) { Vue.mixin = function (mixin: Object) { this.options = mergeOptions(this.options, mixin) return this }}
initMixin
方法的主要作用是在 Vue原型上添加 mixin
这个全局API。再看 initExtend
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构造器, 创建一个"子类", 参数是一个包含组件选项的对象 // API 详细 https://cn.vuejs.org/v2/api/#Vue-extend // ... Vue.extend = function (extendOptions: Object): Function { }}
这个方法在 Vue构造函数上添加了 cid、extend
一个静态属性和一个静态方法。
最后一个 initAssetRegisters
文件
import { ASSET_TYPES } from 'shared/constants'import { isPlainObject, validateComponentName } from '../util/index'export function initAssetRegisters (Vue: GlobalAPI) { /** * Create asset registration methods. */ ASSET_TYPES.forEach(type => { Vue[type] = function (){}}
ASSET_TYPES
这个文件前面见到过:
export const ASSET_TYPES = [ 'component', 'directive', 'filter']
这个方法的主要作用是在 Vue 构造函数上添加全局的 component、directive、filter
, 分别用来注册 全局组件、指令、过滤器
的。
initGlobalAPI
这个方法就说完了。就是在 Vue这个构造函数上定义静态属性和方法。Vue的出生文件是在 Vue原型对象上丰富了内容,现在又再 Vue构造函数上丰富了内容。
到现在 Vue 构造函数上有以下属性和方法
// initGlobalAPIVue.configVue.util = { warn, extend, mergeOptions, defineReactive}Vue.set = setVue.delete = delVue.nextTick = nextTickVue.options = { components: { KeepAlive }, directives: Object.create(null), filters: Object.create(null), _base: Vue}// initUse ***************** global-api/use.jsVue.use = function (plugin: Function | Object) {}// initMixin ***************** global-api/mixin.jsVue.mixin = function (mixin: Object) {}// initExtend ***************** global-api/extend.jsVue.cid = 0Vue.extend = function (extendOptions: Object): Function {}// initAssetRegisters ***************** global-api/assets.jsVue.component =Vue.directive =Vue.filter = function ( id: string, definition: Function | Object): Function | Object | void {}// expose FunctionalRenderContext for ssr runtime helper installationObject.defineProperty(Vue, 'FunctionalRenderContext', { value: FunctionalRenderContext})Vue.version = '__VERSION__'