Vue中mixin和extend的區別和使用場景

Vue中有兩個較爲高級的靜態方法mixin和extend,接下來咱們來討論下關於他們各自的原理和使用場景。javascript

Mixin:

原理:

先來看看官網的介紹:

參數: {Object} mixinjava

用法:api

混入也能夠進行全局註冊。使用時格外當心!一旦使用全局混入,它將影響每個以後建立的 Vue 實例。使用恰當時,這能夠用來爲自定義選項注入處理邏輯。閉包

// 爲自定義的選項 'myOption' 注入一個處理器。
     Vue.mixin({
       created: function () {
         var myOption = this.$options.myOption
         if (myOption) {
           console.log(myOption)
         }
       }
     })
     
     new Vue({
       myOption: 'hello!'
     })
     // => "hello!"
複製代碼

咱們知道,Vue.mixin傳遞的這個參數對象,在初始化Vue實例的時候會merge到options上,下面是Vue源碼中對mixin的操做。函數

// src\core\global-api\mixin.js
 export function initMixin (Vue: GlobalAPI) {
   Vue.mixin = function (mixin: Object) {
     this.options = mergeOptions(this.options, mixin)
     return this
   }
 }
複製代碼
// src\core\instance\index.js
 function Vue (options) {
     if (process.env.NODE_ENV !== 'production' &&
     !(this instanceof Vue)
     ) {
     warn('Vue is a constructor and should be called with the `new` keyword')
     }
     this._init(options)
 }
 
 initMixin(Vue)
 ...
 
 export default Vue
複製代碼

也就是說,mixin只是對咱們在初始化Vue實例時傳遞的配置對象的一個擴展。性能

就像上面官網實例寫的例子,咱們在執行Vue.mixin方法時傳遞一個配置對象進去,對象裏面有個created勾子函數,經過源碼咱們能夠看到這個傳遞進來的對象最終會和咱們在初始化實例也就是new Vue(options)時的這個options合併(經過上面源碼中的mergeOptions方法),保存在option上。ui

使用場景:

當咱們須要全局去注入一些methods,filter或者hooks時咱們就可使用mixin來作。 好比咱們但願每個Vue實例都有一個print方法,咱們就能夠這麼作:this

Vue.mixin({
        methods: {
            print() {
                console.log(`我是一個經過mixin注入的方法!`)
            }
        }
    })
複製代碼

或者咱們想要去監聽在什麼階段時什麼組件被加載了,被卸載了等等,咱們能夠這麼作:spa

Vue.mixin({
        mounted() {
            console.log(`${this.$route.name} component mounted!`)
        },
        destroyed() {
            console.log(`${this.$route.name} component destroyed!`)
        }
    })
複製代碼

若是咱們並不想給每個組件實例都混入這些配置options,而只是個別的組件,最好不要使用mixin,它可能會影響到咱們組件的性能。 prototype

Extend:

原理:

先來看看官網的介紹:

參數: {Object} options

用法:

使用基礎 Vue 構造器,建立一個「子類」。參數是一個包含組件選項的對象。

data 選項是特例,須要注意 - 在 Vue.extend() 中它必須是函數。

data必須是函數是爲了防止各個實例的數據混亂,閉包的應用。

<div id="mount-point"></div>
// 建立構造器
var Profile = Vue.extend({
  template: '<p>{{firstName}} {{lastName}} aka {{alias}}</p>',
  data: function () {
    return {
      firstName: 'Walter',
      lastName: 'White',
      alias: 'Heisenberg'
    }
  }
})
// 建立 Profile 實例,並掛載到一個元素上。
new Profile().$mount('#mount-point')
複製代碼

再來看看源碼裏面關於Vue.extend的實現:

Vue.extend = function (extendOptions: Object): Function {
    extendOptions = extendOptions || {}
    const Super = this
    const SuperId = Super.cid
    const cachedCtors = extendOptions._Ctor || (extendOptions._Ctor = {})
    if (cachedCtors[SuperId]) {
      return cachedCtors[SuperId]
    }

    const name = extendOptions.name || Super.options.name
    if (process.env.NODE_ENV !== 'production' && name) {
      validateComponentName(name)
    }

    const Sub = function VueComponent (options) {
      this._init(options)
    }
    Sub.prototype = Object.create(Super.prototype)
    Sub.prototype.constructor = Sub
    Sub.cid = cid++
    Sub.options = mergeOptions(
      Super.options,
      extendOptions
    )
    Sub['super'] = Super

    // For props and computed properties, we define the proxy getters on
    // the Vue instances at extension time, on the extended prototype. This
    // avoids Object.defineProperty calls for each instance created.
    if (Sub.options.props) {
      initProps(Sub)
    }
    if (Sub.options.computed) {
      initComputed(Sub)
    }

    // allow further extension/mixin/plugin usage
    Sub.extend = Super.extend
    Sub.mixin = Super.mixin
    Sub.use = Super.use

    // create asset registers, so extended classes
    // can have their private assets too.
    ASSET_TYPES.forEach(function (type) {
      Sub[type] = Super[type]
    })
    // enable recursive self-lookup
    if (name) {
      Sub.options.components[name] = Sub
    }

    // keep a reference to the super options at extension time.
    // later at instantiation we can check if Super's options have
    // been updated.
    Sub.superOptions = Super.options
    Sub.extendOptions = extendOptions
    Sub.sealedOptions = extend({}, Sub.options)

    // cache constructor
    cachedCtors[SuperId] = Sub
    return Sub
  }
}
複製代碼

首先咱們能夠看到,extend方法返回的Sub實際上是一個構造函數,並且繼承自Vue,也就是說extend方法返回的是Vue的一個子類。

Sub.prototype = Object.create(Super.prototype)
    Sub.prototype.constructor = Sub
複製代碼

這兩行代碼其實就是實現Sub對Vue的繼承,源碼中有一行是

const Super = this
複製代碼

因此這裏的Super指的就是Vue。

Sub.options = mergeOptions(
     Super.options,
     extendOptions
)
複製代碼

咱們注意到在extend中也會對傳進來的配置option和Vue原來的options作一個合併。

使用場景:

當咱們不須要全局去混入一些配置,好比,咱們想要得到一個component。咱們可使用Vue.component(),也可使用Vue.extend()。

const ChildVue = Vue.extend({
    ...options
})

new ChildVue({
    ...options
})
複製代碼

注意extend獲得的是一個Vue的子類,也就是構造函數。

區別:

mixin是對Vue類的options進行混入。全部Vue的實例對象都會具有混入進來的配置行爲。

extend是產生一個繼承自Vue類的子類,只會影響這個子類的實例對象,不會對Vue類自己以及Vue類的實例對象產生影響

相關文章
相關標籤/搜索