Vue源码学习二 是对Vue的原型对象的包装,最后从Vue的出生文件导出了 Vue这个构造函数

来到 src/core/index.js 代码是:

  1. import Vue from './instance/index'
  2. import { initGlobalAPI } from './global-api/index'
  3. import { isServerRendering } from 'core/shared/env'
  4. import { FunctionalRenderContext } from 'core/vdom/create-functional-component'
  5. // 将 Vue 构造函数作为参数, 传递给 initGlobalAPI 方法
  6. // 向Vue.prototype 上添加一些静态属性和方法
  7. initGlobalAPI(Vue)
  8. Object.defineProperty(Vue.prototype, '$isServer', {
  9. get: isServerRendering
  10. })
  11. Object.defineProperty(Vue.prototype, '$ssrContext', {
  12. get () {
  13. /* istanbul ignore next */
  14. return this.$vnode && this.$vnode.ssrContext
  15. }
  16. })
  17. // expose FunctionalRenderContext for ssr runtime helper installation
  18. Object.defineProperty(Vue, 'FunctionalRenderContext', {
  19. value: FunctionalRenderContext
  20. })
  21. Vue.version = '__VERSION__'
  22. // http://hcysun.me/vue-design/art/2vue-constructor.html#with-compiler
  23. export default Vue

看第一句 import Vue from './instance/index', 导入了Vue这个构造函数,且原型在上面已经添加了一些属性和方法。

然后 initGlobalAPI(Vue)执行 initGlobalAPI 方法并且将 Vue构造函数就为参数调用。
又再 Vue的原型上添加了两个只读的属性 $isServer、$ssrContext。并且再 Vue构造函数上定义了 FunctionalRenderContext静态属性,之所以在 Vue构造函数上定义,是因为在 ssr的时候要使用它。最后 Vue.version = '__VERSION__'又在 Vue构造函数上定义了version,即版本号。

然后再看 initGlobalAPI 方法的来源地, 它主要是丰富 Vue构造函数,在构造函数上添加静态属性和方法。import { initGlobalAPI } from './global-api/index'。 来到 ./global-api/index.js文件中

  1. export function initGlobalAPI (Vue: GlobalAPI) {
  2. // config
  3. const configDef = {}
  4. configDef.get = () => config
  5. if (process.env.NODE_ENV !== 'production') {
  6. configDef.set = () => {
  7. warn(
  8. 'Do not replace the Vue.config object, set individual fields instead.'
  9. )
  10. }
  11. }
  12. // Vue构造函数上添加config属性, 也是只读的属性。
  13. // Vue.config 代理的是从../config文件导出的对象
  14. Object.defineProperty(Vue, 'config', configDef)

首先是这样的一段代码, 这段代码是在 Vue构造函数上添加 config属性, 他也是一个只读的属性,和 $data$prop是一样的。当你试图修改这个属性时,在非生产环境下会给你提醒warn
这个 config从哪里来的呢, 这个文件的最顶部 import config from '../config'
所以 Vue.config 代理的是从 core/config导入的config对象。

然后是这样一段代码:

  1. // exposed shared methods.
  2. // NOTE: these are not considered part of the public API - avoid relying on
  3. // them unless you are aware of the risk.
  4. Vue.util = {
  5. warn,
  6. extend,
  7. mergeOptions,
  8. defineReactive
  9. }

这是在Vue原型上添加了一个 util属性,它是一个对象。这个对象有四个属性 warn、extend、mergeOptions、defineReactive。他们都是来自于 src/core/util/index文件中。官网上没有这些api的说明, 也不推荐使用。

然后是一段这样的代码:

  1. Vue.set = set
  2. Vue.delete = del
  3. Vue.nextTick = nextTick
  4. // options 通过Object.create()创建的一个空对象
  5. Vue.options = Object.create(null)

上面这段代码是在 Vue构造函数上又添加了四个属性 set、delete、nextTickoptionsoptions是通过 Object.create(null)创建的一个空对象。下面的代码即丰富了 options这个对象。

  1. ASSET_TYPES.forEach(type => {
  2. Vue.options[type + 's'] = Object.create(null)
  3. })
  4. // this is used to identify the "base" constructor to extend all plain-object
  5. // components with in Weex's multi-instance scenarios.
  6. Vue.options._base = Vue

ASSET_TYPES是上面呢?很明显他是一个数组,遍历它的每一个属性 + s 并且添加到 Vue.options上。并且初始赋值的都是 Object.create(null)。看一下 ASSET_TYPES来自src/shared/constants.js文件。

  1. export const ASSET_TYPES = [
  2. 'component',
  3. 'directive',
  4. 'filter'
  5. ]

可以看到 ASSET_TYPES是这么一个数组。原来是通过遍历向 Vue.options中添加 components、directives、filters

到目前,Vue.options现在是这样样子:

  1. Vue.options = {
  2. components: Object.create(null),
  3. directives: Object.create(null),
  4. filters: Object.create(null),
  5. _base: Vue
  6. }

然后继续向下看是这样的一句代码

  1. extend(Vue.options.components, builtInComponents)

extend是 Vue的一个工具方法,在 src/shared/util.js文件中

  1. /**
  2. * Mix properties into target object.
  3. */
  4. export function extend (to: Object, _from: ?Object): Object {
  5. for (const key in _from) {
  6. to[key] = _from[key]
  7. }
  8. return to
  9. }

主要作用是将一个对象的属性混入到另外一个对象中。
那么上面的 extend(Vue.options.components, builtInComponents)的意思就是将 builtInComponents对象的属性混入到 Vue.options.components对象中。那么builtInComponents对象是啥呢? 来到 src/core/components/indes.js文件中:

  1. import KeepAlive from './keep-alive'
  2. export default {
  3. KeepAlive
  4. }

就是将 KeepAlive 这个属性添加到 Vue.options.conponents中。

那么到目前为止, Vue.options对象已经变成了这个样子

  1. Vue.options = {
  2. components: {
  3. KeepAlive
  4. },
  5. directives: Object.create(null),
  6. filters: Object.create(null),
  7. _base: Vue
  8. }

再看这个文件的最后一部分代码

  1. initUse(Vue)
  2. initMixin(Vue)
  3. initExtend(Vue)
  4. initAssetRegisters(Vue)

依此调用了四个方法,都是将 Vue这个构造函数作为其参数。initUse、initMixin、initExtend、initAssetRegisters四个方法分别来自 ./global-api/use.js./global-api/mixin.js./global-api/extend.js./global-api/assets.js文件。

先看 initUse文件:

  1. // 全局的 Vue.use() 用来安装插件的方法
  2. export function initUse (Vue: GlobalAPI) {
  3. Vue.use = function(){}
  4. }

该方法的主要作用是在 Vue上添加 use方法,也就是用来安装 Vue插件的全局API Vue.use()

initMixin文件

  1. // 在Vue上添加mixin的全局API
  2. export function initMixin (Vue: GlobalAPI) {
  3. Vue.mixin = function (mixin: Object) {
  4. this.options = mergeOptions(this.options, mixin)
  5. return this
  6. }
  7. }

initMixin方法的主要作用是在 Vue原型上添加 mixin这个全局API。再看 initExtend

initExtend文件

  1. export function initExtend (Vue: GlobalAPI) {
  2. /**
  3. * Each instance constructor, including Vue, has a unique
  4. * cid. This enables us to create wrapped "child
  5. * constructors" for prototypal inheritance and cache them.
  6. */
  7. Vue.cid = 0
  8. let cid = 1
  9. /**
  10. * Class inheritance
  11. */
  12. // 使用基础Vue构造器, 创建一个"子类", 参数是一个包含组件选项的对象
  13. // API 详细 https://cn.vuejs.org/v2/api/#Vue-extend
  14. // ...
  15. Vue.extend = function (extendOptions: Object): Function {
  16. }
  17. }

这个方法在 Vue构造函数上添加了 cid、extend一个静态属性和一个静态方法。

最后一个 initAssetRegisters文件

  1. import { ASSET_TYPES } from 'shared/constants'
  2. import { isPlainObject, validateComponentName } from '../util/index'
  3. export function initAssetRegisters (Vue: GlobalAPI) {
  4. /**
  5. * Create asset registration methods.
  6. */
  7. ASSET_TYPES.forEach(type => {
  8. Vue[type] = function (){}
  9. }

ASSET_TYPES这个文件前面见到过:

  1. export const ASSET_TYPES = [
  2. 'component',
  3. 'directive',
  4. 'filter'
  5. ]

这个方法的主要作用是在 Vue 构造函数上添加全局的 component、directive、filter, 分别用来注册 全局组件、指令、过滤器的。

initGlobalAPI这个方法就说完了。就是在 Vue这个构造函数上定义静态属性和方法。Vue的出生文件是在 Vue原型对象上丰富了内容,现在又再 Vue构造函数上丰富了内容。

到现在 Vue 构造函数上有以下属性和方法

  1. // initGlobalAPI
  2. Vue.config
  3. Vue.util = {
  4. warn,
  5. extend,
  6. mergeOptions,
  7. defineReactive
  8. }
  9. Vue.set = set
  10. Vue.delete = del
  11. Vue.nextTick = nextTick
  12. Vue.options = {
  13. components: {
  14. KeepAlive
  15. },
  16. directives: Object.create(null),
  17. filters: Object.create(null),
  18. _base: Vue
  19. }
  20. // initUse ***************** global-api/use.js
  21. Vue.use = function (plugin: Function | Object) {}
  22. // initMixin ***************** global-api/mixin.js
  23. Vue.mixin = function (mixin: Object) {}
  24. // initExtend ***************** global-api/extend.js
  25. Vue.cid = 0
  26. Vue.extend = function (extendOptions: Object): Function {}
  27. // initAssetRegisters ***************** global-api/assets.js
  28. Vue.component =
  29. Vue.directive =
  30. Vue.filter = function (
  31. id: string,
  32. definition: Function | Object
  33. ): Function | Object | void {}
  34. // expose FunctionalRenderContext for ssr runtime helper installation
  35. Object.defineProperty(Vue, 'FunctionalRenderContext', {
  36. value: FunctionalRenderContext
  37. })
  38. Vue.version = '__VERSION__'

Vue源码学习三 ———— Vue构造函数包装的更多相关文章

  1. vue 源码学习三 vue中如何生成虚拟DOM

    vm._render 生成虚拟dom 我们知道在挂载过程中, $mount 会调用 vm._update和vm._render 方法,vm._updata是负责把VNode渲染成真正的DOM,vm._ ...

  2. Vue源码学习二 ———— Vue原型对象包装

    Vue原型对象的包装 在Vue官网直接通过 script 标签导入的 Vue包是 umd模块的形式.在使用前都通过 new Vue({}).记录一下 Vue构造函数的包装. 在 src/core/in ...

  3. Vue源码学习1——Vue构造函数

    Vue源码学习1--Vue构造函数 这是我第一次正式阅读大型框架源码,刚开始的时候完全不知道该如何入手.Vue源码clone下来之后这么多文件夹,Vue的这么多方法和概念都在哪,完全没有头绪.现在也只 ...

  4. Vue源码学习一 ———— Vue项目目录

    Vue 目录结构 可以在 github 上通过这款 Chrome 插件 octotree 查看Vue的文件目录.也可以克隆到本地.. Vue 是如何规划目录的 scripts ------------ ...

  5. 【Vue源码学习】依赖收集

    前面我们学习了vue的响应式原理,我们知道了vue2底层是通过Object.defineProperty来实现数据响应式的,但是单有这个还不够,我们在data中定义的数据可能没有用于模版渲染,修改这些 ...

  6. Vue源码学习(一):调试环境搭建

    最近开始学习Vue源码,第一步就是要把调试环境搭好,这个过程遇到小坑着实费了点功夫,在这里记下来 一.调试环境搭建过程 1.安装node.js,具体不展开 2.下载vue项目源码,git或svn等均可 ...

  7. 最新 Vue 源码学习笔记

    最新 Vue 源码学习笔记 v2.x.x & v3.x.x 框架架构 核心算法 设计模式 编码风格 项目结构 为什么出现 解决了什么问题 有哪些应用场景 v2.x.x & v3.x.x ...

  8. Vue源码分析(二) : Vue实例挂载

    Vue源码分析(二) : Vue实例挂载 author: @TiffanysBear 实例挂载主要是 $mount 方法的实现,在 src/platforms/web/entry-runtime-wi ...

  9. Vue2.x源码学习笔记-Vue构造函数

    我们知道使用vue.js开发应用时,都是new Vue({}/*options*/) 那Vue构造函数上有哪些静态属性和方法呢?其原型上又有哪些方法呢? 一般我都会在浏览器中输入Vue来look se ...

随机推荐

  1. python3+Appium自动化13-H5元素定位实践案例

    测试场景 启动钉钉app进入工作H5页面,点击考勤签到 查看webview上元素 1.电脑上打开chrome浏览器输入:chrome://inspect/#devices 2.Discover USB ...

  2. Murano为镜像包添加Root用户密码

    1. 安装dib-utils Dib Utils 是 diskimage-builder 工程的一部分,但是他们也用于 diskimage-builder 工程外部. 因为基于云的磁盘空间已经溢出,推 ...

  3. python文件操作和集合(三)

    对文件的操作分三步: 1.打开文件获取文件的句柄,句柄就理解为这个文件 2.通过文件句柄操作文件 3.关闭文件. 文件基本操作:         f = open('file.txt','r') #以 ...

  4. CF 540D——Bad Luck Island——————【概率dp】

    Bad Luck Island time limit per test 2 seconds memory limit per test 256 megabytes input standard inp ...

  5. 【Iperf】iperf测试wlan的性能

    1.概念: iperf命令是一个网络性能测试工具.iperf可以测试TCP和UDP带宽质量. iperf可以测量最大TCP带宽,具有多种参数和UDP特性.iperf可以报告带宽,延迟抖动和数据包丢失. ...

  6. transient和volatile

    transient和volatile两个关键字一个用于对象序列化,一个用于线程同步,都是Java中比较高阶的话题,简单总结一下. transient transient是类型修饰符,只能用来修饰字段. ...

  7. 负载均衡配置下的不同服务器【Linux】文件同步问题

    负载均衡配置下的不同服务器[Linux]文件同步问题2017年04月13日 22:04:28 守望dfdfdf 阅读数:2468 标签: linux负载均衡服务器 更多个人分类: 工作 问题编辑版权声 ...

  8. JAVA SE collection接口

    collection接口:{Set,List,Queue} Set:无序集合,元素不可重复          List:有序集合,元素可重复          Queue:队列 Set{EnumSet ...

  9. 在 CentOS7 上安装 swftools

    1.从官网下载 swftools,这里下载的是 0.9.2 版本: wget http://www.swftools.org/swftools-0.9.2.tar.gz 2.下载后得到 swftool ...

  10. 解决dubbo的服务发布注解@service不能和事务注解不能共用的方案

    最近在项目的开发中遇到了一个问题,就是服务提供方使用@service发布dubbo服务时候,服务消费方@Reference无法注入bean导致空指针异常的问题.分析原因为@service注解并没有将服 ...