1.4 子类构造器

选项校验介绍完后,在正式进入合并策略之前,还需要先了解一个东西:子类构造器。为什么需要先提到子类构造器呢?

按照前面的知识,Vue内部提供了四个默认选项,关键的三个是components,directives,filter。那么当我们传递一个选项配置到Vue进行初始化,所需要合并的选项好像也仅仅是那关键的三个默认选项而已,那么源码中大篇幅做的选项合并策略又是针对什么场景呢?答案就是这个子类构造器。

Vue提供了一个Vue.extend的静态方法,它是基于基础的Vue构造器创建一个“子类”,而这个子类所传递的选项配置会和父类的选项配置进行合并。这是选项合并场景的由来。

因此有不要先了解子类构造器的实现。下面例子中,我们创建了一个Child的子类,它继承于父类Parent,最终将子类挂载到#app元素上。最终获取的data便是选项合并后的结果。

  1. var Parent = Vue.extend({
  2. data() {
  3. test: '父类'
  4. test1: '父类1'
  5. }
  6. })
  7. var Child = Parent.extend({
  8. data() {
  9. test: '子类',
  10. test2: '子类1'
  11. }
  12. })
  13. var vm = new Child().$mount('#app');
  14. console.log(vm.$data);
  15. // 结果
  16. {
  17. test: '子类',
  18. test1: '父类1',
  19. test2: '子类1'
  20. }

Vue.extend的实现思路很清晰,创建了一个Sub的类,这个类的原型指向了父类,并且子类的options会和父类的options进行合并,mergeOptions的其他细节接下来会重点分析。

  1. Vue.extend = function (extendOptions) {
  2. extendOptions = extendOptions || {};
  3. var Super = this;
  4. var name = extendOptions.name || Super.options.name;
  5. if (name) {
  6. validateComponentName(name); // 校验子类的名称是否符合规范
  7. }
  8. // 创建子类构造器
  9. var Sub = function VueComponent (options) {
  10. this._init(options);
  11. };
  12. Sub.prototype = Object.create(Super.prototype); // 子类继承于父类
  13. Sub.prototype.constructor = Sub;
  14. Sub.cid = cid++;
  15. // 子类和父类构造器的配置选项进行合并
  16. Sub.options = mergeOptions(
  17. Super.options,
  18. extendOptions
  19. );
  20. return Sub // 返回子类构造函数
  21. };