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方法和屬性。