摘要:概念模式就是一些提供能夠被一個或者一組子類簡單繼承功能的類意在重用其功能。示例下面通過一個簡單的例子來演示這個模式混入模式的實現(xiàn)不指定特定方法名的時候,將后者所有的方法都添加到前者里優(yōu)缺點優(yōu)點有助于減少系統(tǒng)中的重復(fù)功能及增加函數(shù)復(fù)用。
概念
Mixin模式就是一些提供能夠被一個或者一組子類簡單繼承功能的類,意在重用其功能。在面向?qū)ο蟮恼Z言中,我們會通過接口繼承的方式來實現(xiàn)功能的復(fù)用。但是在javascript中,我們沒辦法通過接口繼承的方式,但是我們可以通過javascript特有的原型鏈屬性,將功能引用復(fù)制到原型鏈上,達(dá)到功能的注入。
示例下面通過一個簡單的例子來演示這個模式
var Car = function(settings) { this.model = settings.model || "no model provided" this.color = settings.color || "no color provided" } var Mixin = function() {} Mixin.prototype = { driveForward: function() { console.log("drive forward") }, driveBackward: function() { console.log("drive backward") }, driveSideways: function() { console.log("drive sideways") } } //混入模式的實現(xiàn) function Merge(recClass, giveClass) { if(arguments.length > 2) { for(var i = 2, lenth = arguments.length; i < lenth ; ++ i) { var methodName = arguments[i] recClass.prototype[methodName] = giveClass.prototype[methodName] } }else { for(var methodName in giveClass.prototype) { if(!recClass.prototype[methodName]) { recClass.prototype[methodName] = giveClass.prototype[methodName] } } } } Merge(Car, Mixin, "driveForward", "driveBackward") var myCar = new Car({ model: "BMW", color: "blue" }) myCar.driveForward() //drive forward myCar.driveBackward() //drive backward //不指定特定方法名的時候,將后者所有的方法都添加到前者里 Merge(Car, Mixin) var mySportsCar = new Car({ model: "Porsche", color: "red" }) mySportsCar.driveForward() //drive forward優(yōu)缺點
優(yōu)點
有助于減少系統(tǒng)中的重復(fù)功能及增加函數(shù)復(fù)用。當(dāng)一個應(yīng)用程序可能需要在各種對象實例中共享行為時,我們可以通過在Mixin中維持這種共享功能并專注于僅實現(xiàn)系統(tǒng)中真正不同的功能,來輕松避免任何重復(fù)。
缺點
有些人認(rèn)為將功能注入對象原型中會導(dǎo)致原型污染和函數(shù)起源方面的不確定性。
vue中關(guān)于混入的代碼目錄/src/core/global-api/mixin.js
可以看到vue源碼中是通過mergeOptions來合并配置到options上
export function initMixin (Vue: GlobalAPI) { Vue.mixin = function (mixin: Object) { this.options = mergeOptions(this.options, mixin) return this } }
下面我們來看合并配置的相關(guān)代碼/src/core/instance/init.js
當(dāng)執(zhí)行new Vue的時候options._isComponent為false,會走else的分支
export function initMixin (Vue: Class) { Vue.prototype._init = function (options?: Object) { const vm: Component = this // a uid vm._uid = uid++ let startTag, endTag /* istanbul ignore if */ if (process.env.NODE_ENV !== "production" && config.performance && mark) { startTag = `vue-perf-start:${vm._uid}` endTag = `vue-perf-end:${vm._uid}` mark(startTag) } // a flag to avoid this being observed vm._isVue = true // merge options if (options && options._isComponent) { // optimize internal component instantiation // since dynamic options merging is pretty slow, and none of the // internal component options needs special treatment. initInternalComponent(vm, options) } else { vm.$options = mergeOptions( //合并配置 resolveConstructorOptions(vm.constructor), options || {}, vm ) } /* istanbul ignore else */ if (process.env.NODE_ENV !== "production") { initProxy(vm) } else { vm._renderProxy = vm } // expose real self vm._self = vm initLifecycle(vm) initEvents(vm) initRender(vm) callHook(vm, "beforeCreate") initInjections(vm) // resolve injections before data/props initState(vm) initProvide(vm) // resolve provide after data/props callHook(vm, "created") /* istanbul ignore if */ if (process.env.NODE_ENV !== "production" && config.performance && mark) { vm._name = formatComponentName(vm, false) mark(endTag) measure(`vue ${vm._name} init`, startTag, endTag) } if (vm.$options.el) { vm.$mount(vm.$options.el) } } }
下面來看mergeOptions的實現(xiàn)src/core/util/options.js
mergeField將this.options(parent)和需要混入的對象mixin(child)合并在this.options上面
/** * Merge two option objects into a new one. * Core utility used in both instantiation and inheritance. */ export function mergeOptions ( parent: Object, child: Object, vm?: Component ): Object { if (process.env.NODE_ENV !== "production") { checkComponents(child) } if (typeof child === "function") { child = child.options } normalizeProps(child, vm) normalizeInject(child, vm) normalizeDirectives(child) const extendsFrom = child.extends if (extendsFrom) { parent = mergeOptions(parent, extendsFrom, vm) } if (child.mixins) { for (let i = 0, l = child.mixins.length; i < l; i++) { parent = mergeOptions(parent, child.mixins[i], vm) } } const options = {} let key for (key in parent) { mergeField(key) } for (key in child) { if (!hasOwn(parent, key)) { mergeField(key) } } function mergeField (key) { const strat = strats[key] || defaultStrat options[key] = strat(parent[key], child[key], vm, key) } return options }參考
《JavaScript設(shè)計模式》
JS設(shè)計模式系列文章JS設(shè)計模式之Obeserver(觀察者)模式、Publish/Subscribe(發(fā)布/訂閱)模式
JS設(shè)計模式之Factory(工廠)模式
JS設(shè)計模式之Singleton(單例)模式
JS設(shè)計模式之Facade(外觀)模式
JS設(shè)計模式之Module(模塊)模式、Revealing Module(揭示模塊)模式
JS設(shè)計模式之Mixin(混入)模式
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/103895.html
摘要:使用替換目標(biāo)在第三篇文章中,我們使用來抽離了注入依賴項的公共邏輯。成果通過作用域插槽,我們有效地避免了第三方組件由于混入而可能造成的命名沖突以及隱式依賴等問題。 04 使用 slot 替換 mixin 目標(biāo) 在第三篇文章中,我們使用 mixin 來抽離了注入 toggle 依賴項的公共邏輯。在 react 中,類似的需求是通過 HOC 的方式來解決的,但是仔細(xì)想想的話,react 在早...
摘要:在中,我們是否也有一些手段或特性來提高組件的復(fù)用程度和靈活性呢答案當(dāng)然是有的,那就是。成果通過實現(xiàn),我們成功將注入的邏輯抽離了出來,這樣每次需要共享組件的狀態(tài)和方法時,混入該即可。 03 使用 mixin 來增強 Vue 組件 目標(biāo) 之前一篇文章中,我們雖然將 toggle 組件劃分為了 toggle-button、toggle-on 和 toggle-off 三個子組件,且一切運行良...
摘要:前言最近開發(fā)的頁面以及功能大都以表格為主,接口獲取來的數(shù)據(jù)大都是需要經(jīng)過處理,比如時間戳需要轉(zhuǎn)換,或者狀態(tài)碼的轉(zhuǎn)義。首先,還是在文件中定義一個狀態(tài)碼對應(yīng)對象,這里我們將其對應(yīng)的內(nèi)容設(shè)為段落。 前言 最近開發(fā)的頁面以及功能大都以表格為主,接口獲取來的 JSON 數(shù)據(jù)大都是需要經(jīng)過處理,比如時間戳需要轉(zhuǎn)換,或者狀態(tài)碼的轉(zhuǎn)義。對于這樣的問題,各大主流框架都提供了類似于過濾的方法,在 Vue ...
閱讀 2345·2023-04-25 14:29
閱讀 1477·2021-11-22 09:34
閱讀 2715·2021-11-22 09:34
閱讀 3398·2021-11-11 10:59
閱讀 1864·2021-09-26 09:46
閱讀 2238·2021-09-22 16:03
閱讀 1929·2019-08-30 12:56
閱讀 485·2019-08-30 11:12