Vue2.6.x源码阅读 - 5.源码阅读-core-Vue构造函数

阅读学习Vue源码/src目录下的core文件夹内Vue构造函数相关的代码

Vue构造函数

  • core目录下的index.jsVue构造函数依旧进行了一定程度的封装,先除开封装的内容,直接进入到Vue真正的构造函数所在的位置src/core/instance/index.js

    /* Vue 构造函数 */
    function Vue (options) {
      // 入参 options 即为开发者new一个Vue实例时,Vue中传入的带有data、method、watch等属性的对象,在日常代码中,直接使用 this 指代。
      if (process.env.NODE_ENV !== 'production' &&
        !(this instanceof Vue) // 判断是否通过 new 调用 Vue 构造函数
      ) {
        warn('Vue is a constructor and should be called with the `new` keyword')
      }
      this._init(options) // 初始化 Vue 实例,方法定义于 Vue 的 prototype 中
    }
    
    initMixin(Vue) // 混入初始化方法,构造函数中的 Vue.prototype._init()方法来自于其中
    stateMixin(Vue) // 混入 状态处理 的方法
    eventsMixin(Vue) // 混入 事件 的方法
    lifecycleMixin(Vue) // 混入 生命周期 的方法
    renderMixin(Vue) // 混入 渲染相关 的方法
    
    export default Vue
  • ⭐️ 构造函数所在的文件(src/core/instance/index.js)内容较少,但需要注意各个方法的执行顺序。构造函数在实际样例代码调用new Vue(options)才会执行,各类Mixin方法都先于构造函数执行,这些方法将包括prototype方法、状态处理、事件、生命周期、渲染相关的方法都预先写入至构造函数内,所以在实际调用构造方法时,Vue实例内容已经具有一定的复杂程度。

  • 当然实例所挂载的内容也不仅限于src/core/instance/index.js文件,其外层的src/core/index.js以及再外层的src/platforms/web/runtime/index.js也同样进行了一定程度的挂载。从入口文件开始到构造函数,一个Vue实例经过了三层的封装。最外层的封装其实能够理解,是基于平台入口的不同而会存在挂载内容的区别。中层与内层的挂载内容区分依旧比较费解,初步认为是处于代码结构的考虑,需要更加深入的学习。

initMixin

  • 回到构造函数,进入到含有初始化方法的initMixin(),由于方法较长,所以按顺序分别进行分析。

    1. 初始化定义

    2. 性能测试,development模式下,可开启core/config.js中的性能分析配置performance: true以测试各个Vue组件在初始化阶段的性能表现。

      • 在这里也可以看出core/config.js这份文件用于更改Vue内部的一些配置,这些配置不开放给实际开发者,但支持开发者更改在调试时使用。

      • 这段代码中有一处非代码逻辑的细节,可以看到有一些istanbul开头的注释,如/* istanbul ignore if */istanbul为一个用于检查代码覆盖率的JavaScript库。在不开启性能分析配置的情况下,性能测试相关的两个if-else代码块无法被覆盖到,故加了这一段注释用于忽略覆盖率检测。扩展:如果需要忽略整个文件,可在文件开头增加/* istanbul ignore next */实现。

      • 另一个关于代码顺序的细节,我们可以发现片段一的定义的代码内容是很少的,除了需要在性能分析中使用的变量,均未在片段一内进行处理。可以合理猜测这里的处理是为了让初始化阶段的性能更加精确。结合下面片段三的内容,也可以得出当前初始化方法内的性能,是用于测试实例创建,至生命周期created为止所消耗的时间。

      • 通过performance API可以获取到Vue源码所记录的性能记录。

    3. options合并。else部分的合并逻辑中,可以发现vm.constructor.options内部是有内容的,甚至已经挂载了KeepAlive等组件,以及一些命令。构造函数自带的options就来自于上文所述的入口文件的多层封装。

    4. 丰富Vue实例内容,赋值各类属性,以及生命周期方法beforeCreatecreated的调用。initProxy部分可参考学习。

      • 通过观察初始化各类属性的方法以及beforeCreatecreated两个生命周期方法的顺序,可以知道datapropsinjectsprovides等数据属性在created时候已经被创建,且存在内容。而此时与dom相关的属性依旧为空状态。

      • 关于实例的属性,带$符号以及下划线的属性一般都为实例的私有属性,而带$符号的属性一般认为为只读属性。

      • 关于initRender方法注释中所说的“创建元素的方法”即createElement,将VNode转换为真实的的dom,也是自定义render方法中的第一个参数。经常能够在那些可自定义dom的组件中使用到。

    5. ⭐️调用mount方法挂载组件。

      • 可以发现构造函数所在的文件并没有该方法的定义,但$mount方法又充满了既视感。该方法会根据platform不同会有所区别,结合web模式下入口文件中的内容(可见上一篇4.源码阅读-platform)可知,该方法已经挂载在Vue.prototype上。而代码内容由运行模式决定(该方法于6.源码阅读-core-组件挂载进行解析)。

    6. 关于4中代码的initState方法,这里进行一定的展开。以下代码中提及的observedefineReactive方法于7.源码阅读-core-响应式原理中解析

最后更新于

这有帮助吗?