version: 2.5.17-beta.0
首先从package.json文件开始看,scripts里有一条命令是dev:
"dev": "rollup -w -c scripts/config.js --environment TARGET:web-full-dev"
它运行了scripts/config.js文件,这个文件生成了rollup打包器的配置,这个文件里web-full-dev对应的配置是这样的:
// Runtime+compiler development build (Browser) 'web-full-dev': { entry: resolve('web/entry-runtime-with-compiler.js'), dest: resolve('dist/vue.js'), format: 'umd', env: 'development', alias: { he: './entity-decoder' }, banner }
entry入口是web/entry-runtime-with-compiler.js这个文件,但是直接找不到web目录在哪里,原来这里是自己定义了一个路径别名,scripts/config.js里有方法专门来转换别名路径变成真正的路径:
const aliases = require('./alias') const resolve = p => { const base = p.split('/')[0] if (aliases[base]) { return path.resolve(aliases[base], p.slice(base.length + 1)) } else { return path.resolve(__dirname, '../', p) } }
这里引入的alias正是别名对应的真实路径:
const path = require('path') const resolve = p => path.resolve(__dirname, '../', p) module.exports = { vue: resolve('src/platforms/web/entry-runtime-with-compiler'), compiler: resolve('src/compiler'), core: resolve('src/core'), shared: resolve('src/shared'), web: resolve('src/platforms/web'), weex: resolve('src/platforms/weex'), server: resolve('src/server'), entries: resolve('src/entries'), sfc: resolve('src/sfc') }
这时就能知道,web/entry-runtime-with-compiler.js对应的路径是src/platforms/web/entry-runtime-with-compiler.js。
打开entry-runtime-with-compiler.js文件,发现这样一句:
import Vue from './runtime/index'
于是打开runtime/index.js,发现这样一句:
import Vue from 'core/index'
打开core/index.js,发现这样一句:
import Vue from './instance/index'
打开instance/index.js,发现Vue构造函数就在这里:
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) }
这里做了判断,如果是开发环境而不是生产环境,而且实例化vue对象的时候没有使用new操作符,就会报一个警告,然后针对传入的options执行之后的操作。
为什么(this instanceof Vue)这一句可以判断是否使用了new操作符?
已new来调用构造函数会经历4个步骤:
- 创建一个新对象;
- 将构造函数的作用域赋给新对象(因此this 就指向了这个新对象);
- 执行构造函数中的代码(为这个新对象添加属性);
- 返回新对象。
而instanceof用来检测Vue构造函数的prototype是否存在于this的原型链上,换句话说,如果使用new实例化的时候,this就指向了这个新创建的对象,这时this instanceof Vue这句话的意思就是判断新创建的对象是否是Vue类型的,也就相当于判断新实例对象的constructor是否是Vue构造函数。
initGlobalAPI(Vue)
从函数名字可以看出它的意思,为Vue构造函数初始化全局API,也就是官方文档里列出来的那一串API列表,它们都是直接挂在Vue构造函数上的属性。
initGlobalAPI在core/global-api/index.js这个文件里定义。
//initGlobalAPI初始化全局API 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构造函数定义一个叫做config的属性,官方API文档里写“Vue.config 是一个对象,包含 Vue 的全局配置。” //通过上面对configDef这个属性描述符的定义,可以发现这个Vue.config是一个访问器属性,而不是数据属性 //因为它拥有get和set方法,专门处理读取和修改它的动作 //它的get方法直接返回core/config.js这个文件定义的全局配置 //它的set方法会报一个警告,不要替换整个Vue.config对象,而是设置单个配置项 // 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里的方法并不是全局API,避免依赖它们除非你知道它们的风险 Vue.util = { warn, extend, mergeOptions, defineReactive } //warn方法,在core/util/debug.js里,报错方法 //extend方法,在shared/util.js里,用于将一个对象的多个属性加到另一个对象上去 //mergeOptions,在core/util/options.js里,用于按不同参数的策略合并option //defineReactive,在core/observer/index Vue.set = set //set方法,在core/observer/index.js里,用于给对象设置一个响应式属性。如果这个属性被删除那就会触发通知。 Vue.delete = del //delete方法,在core/observer/index.js里,删除一个属性并且触发试图更新如果需要的话 Vue.nextTick = nextTick //nextTick方法,在core/util/next-tick.js里,DOM更新循环结束之后执行延迟回调 Vue.options = Object.create(null) ASSET_TYPES.forEach(type => { Vue.options[type + 's'] = Object.create(null) }) //Vue.options.components,Vue.options.directives,Vue.options.filters // 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) //给Vue.options.components增加内建component,KeepAlive, //(extend方法,在shared/util.js里,用于将一个对象的多个属性加到另一个对象上去) initUse(Vue)//Vue.use,core/global-api/use.js initMixin(Vue)//Vue.mixin,core/global-api/mixin.js initExtend(Vue)//Vue.extend,core/global-api/extend.js initAssetRegisters(Vue)//Vue.component,Vue.directive,Vue.filter,core/global-api/assets.js }
initGlobalAPI为Vue构造函数添加很多全局API方法和属性。