new Vue到底做了什么

292 阅读2分钟

问题

new Vue到底做了什么?

分析

在使用vue2的时候,需要构造一个Vue实例,以这个实例为根节点去实现数据的渲染;这个时候就出现了new Vue;

猜想

new Vue的时候将传递的options数据都绑定到vue实例上,并且挂载一些可以调用options的方法;

源码考证

version: v2.7.0

入口

调试vue源码,需要将代码clone下来,然后找到对应的入口:src\core\instance\index.ts;这里只看到一个特别简单的Vue函数:

function Vue(options) {
  if (__DEV__ && !(this instanceof Vue)) {
    warn('Vue is a constructor and should be called with the `new` keyword')
  }
  this._init(options)
}
initMixin(Vue)

可以看出,当执行new Vue的时候就只执行了_init这个函数,那么_init从何而来的呢,很显然,能够通过this调用,那么必然是Vue原型上的方法,于是往上查找,通过initMixin这个突破口;

终于在src\core\instance\init.ts找到initMixin这个方法:

Vue.prototype._init = function (options?: Record<string, any>) {
    const vm: Component = this
    // a uid
    vm._uid = uid++
    
    // ...
    
    // merge options
    // 合并选项,让实例拥有全局的配置项,例如:directive、components等等
    if (options && options._isComponent) {
      initInternalComponent(vm, options as any)
    } else {
      vm.$options = mergeOptions(
        resolveConstructorOptions(vm.constructor as any),
        options || {},
        vm
      )
    }
    /* istanbul ignore else */
    if (__DEV__) {
      initProxy(vm)
    } else {
      vm._renderProxy = vm
    }
    // expose real self
    vm._self = vm
    // 初始化实例相关的属性,例如:$parent, $root, $children, $refs等等
    initLifecycle(vm)
    // 初始化自定义事件
    initEvents(vm)
    // 处理插槽和作用于插槽,提供_c和$createElement函数用于创建VNode,接收父组件传递$attrs和$listeners作为响应式数据
    initRender(vm)
    callHook(vm, 'beforeCreate', undefined, false /* setContext */)
    // 处理祖辈传递的inject数据
    initInjections(vm) // resolve injections before data/props
    // 处理组件本身的状态:props、methods、data、computed、watch
    initState(vm)
    // 处理向下传递的provide数据
    initProvide(vm) // resolve provide after data/props
    callHook(vm, 'created')
    
    // ...
    
    if (vm.$options.el) {
      vm.$mount(vm.$options.el)
    }
  }

总结

在进行new Vue的时候,做了以下几件事情:

  1. 执行_init方法;
  2. 合并options配置项;
  3. initLifecycle初始化实例相关的属性:例如parentparent、root、childrenchildren、refs等等;
  4. initEvent初始化自定义事件;
  5. initRender设置DOM更新函数,处理插槽相关信息,将attrsattrs和listeners处理为响应式数据;
  6. callHook(vm, 'beforeCreate')调用钩子函数;
  7. initInjections处理祖辈传递的inject数据;
  8. initState处理自身的状态:props、methods、data、computed、watch;
  9. initProvide处理向下传递的provide数据;
  10. callHook(vm, 'created')调用钩子函数;
  11. 判断是否options中明确了el属性,如果有那么执行挂载函数,进行数据渲染。