從入口文件找到Vue構造函數

version: 2.5.17-beta.0vue

首先從package.json文件開始看,scripts裏有一條命令是dev:ios

"dev": "rollup -w -c scripts/config.js --environment TARGET:web-full-dev"

它運行了scripts/config.js文件,這個文件生成了rollup打包器的配置,這個文件裏web-full-dev對應的配置是這樣的:web

// 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裏有方法專門來轉換別名路徑變成真正的路徑:json

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正是別名對應的真實路徑:api

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。weex

打開entry-runtime-with-compiler.js文件,發現這樣一句:less

import Vue from './runtime/index'

因而打開runtime/index.js,發現這樣一句:ide

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個步驟:

  1. 建立一個新對象;
  2. 將構造函數的做用域賦給新對象(所以this 就指向了這個新對象);
  3. 執行構造函數中的代碼(爲這個新對象添加屬性);
  4. 返回新對象。

而instanceof用來檢測Vue構造函數的prototype是否存在於this的原型鏈上,換句話說,若是使用new實例化的時候,this就指向了這個新建立的對象,這時this instanceof Vue這句話的意思就是判斷新建立的對象是不是Vue類型的,也就至關於判斷新實例對象的constructor是不是Vue構造函數。

initGlobalAPI
從上面依據文件反向找到構造函數的過程,咱們發現了這些文件處理的順序是這樣的:
1.Vue構造函數所在的文件:core/instance/index.js
2.接着是core/index.js
3.而後是platforms/web/runtime/index.js
這其中core/index.js裏有這樣一句:
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方法和屬性。

相關文章
相關標籤/搜索