从入口文件找到Vue构造函数


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个步骤:

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


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM