likes
comments
collection

【源码解析】extend的原理 - 其实就是实现了对Vue的继承

作者站长头像
站长
· 阅读数 85

前言

大家好,在前面几篇文章中我们已经陆续分享了几个关于源码原理性的东西。今天我们继续来学习探索Vue2中另一个API - extend的实现原理。extend是vue中的一个全局api,在我们日常开发中可能很少甚至根本不会用到它。但是存在即合理,既然vue官方为我们提供了这个接口,就说明有些场景还是会用到的。下面我们就来看下extend是干什么的,能解决什么问题以及它的实现原理。

了解extend

  • 简介 extend是vue中的一个全局api,它是一个函数,主要功能就是利用基础 Vue 构造器,创建一个“子类”。参数是一个包含组件选项的对象。说白了其实就是实现了继承功能。

  • 使用场景 那么它的目的是什么呢,为什么要用它去扩展一个Vue的子类呢?大家都知道我们在使用vue开发的一般都是单页面应用,每个页面(组件)的模板都是提前写好的并且是固定的,然后通过路由来控制页面的跳转。并且整个应用只有一个根节点#app,所有的内容都是挂在这个#app节点中的。但是有时候由于业务需要我们可能要去动态的生成一个组件并且要独立渲染到其它元素节点中,诶,这个时候Vue.extend就派上用场了。下面再来看下如何使用。

  • 基本用法

<div id="app"></div>
<div id="other"></div>
const Sub = Vue.extend({
    template:"<h1>{{name}}</h1>",
    data(){
        return {
            name:"Alvin"
        }
    }
});

const sub = new Sub({});
sub.$mount("#other");

如上代码运行后就会将template中的内容渲染到other元素节点上了。

源码解析

了解了extend的使用方法和使用场景,接下来我们就来分析下它的源码,看看它是如何实现的。

从上面代码我们可以看到,整个文件中只有三个方法:initExtend、initProps和initComputed。其中initExtend则是Vue.extend的核心,该方法会在Vue初始化的时候被调用。

  • initExtend函数仅接收一个Vue作为参数,首先进来第一行就是先给Vue添加一个cid属性,从注释来看就是说:“每一个实例,包括Vue本身都会有一个唯一的cid属性,主要用于继承和缓存”。
  • 然后接着又给Vue添加了一个extend方法,该方法接收一个对象参数extendOptions
  • 在extend方法内部首先将this赋值给变量Super。这里因为我们在调用extend方法时,都是通过Vue.extend直接调用的,所以这里的this其实指向的就Vue本身,因此Super也就是Vue。
  • 然后再将Vue的cid属性取出保存到变量SuperId中,然后根据这个SuperId(cid)判断cachedCtors缓存器中是否已经存
    • 如果已经存在,则直接从缓存中获取并返回,不再重新创建
    • 如果不存在继续执行下面的代码
    • 什么情况下会用到这个缓存呢? 当我们多次调用 Vue.extend 并使用了同一个配置项(extendOptions)时就会启用该缓存

  • 接着从对象extendOptions或者Vue的options中获取到组件的名称name,并通过validateComponentName方法对name的合法性进行校验
  • 再下面又创建了一个Sub构造函数,并在该函数中调用了this._init函数,这个_init函数实际上就是Vue原型上的那个_init
  • 构造函数Sub创建后,让Sub的原型通过Object.create重新指向Vue的原型,并让Sub的constructor重定向到Sub(这一步就实现了原型继承)
  • 同样给子类Sub也添加一个cid属性(Sub.cid = cid++)
  • 给Sub添加options属性,通过mergeOptions方法将Vue上的options和传进来的extendOptions进行合并,并赋值给Sub的options属性
  • 接下来,如果Sub的options上有props和computed,还要通过initProps和initComputed对props和computed中的每个属性进行一一劫持,最终还是通过Object.defineProperty实现
  • 定义 extend、mixin、use 这三个静态方法,允许在 Sub 基础上再进一步构造子类
  • 定义 component、filter、directive 三个静态方法
  • 递归组件的原理,如果组件设置了 name 属性,则将自己注册到自己的 components 选项中
  • 最后将Sub添加到缓存器cachedCtors中,同时将Sub return出去

总结

本次分享我们对Vue2中的extend 全局api的使用方法和使用场景进行了简单介绍和分析,最后从源码层面对extend的实现原理进行了梳理。其实总结起来就是通过extend实现了对Vue的继承。好了今天的分享就到这里了。