摘要:概念模式就是一些提供能夠被一個(gè)或者一組子類簡(jiǎn)單繼承功能的類意在重用其功能。示例下面通過一個(gè)簡(jiǎn)單的例子來演示這個(gè)模式混入模式的實(shí)現(xiàn)不指定特定方法名的時(shí)候,將后者所有的方法都添加到前者里優(yōu)缺點(diǎn)優(yōu)點(diǎn)有助于減少系統(tǒng)中的重復(fù)功能及增加函數(shù)復(fù)用。
概念
Mixin模式就是一些提供能夠被一個(gè)或者一組子類簡(jiǎn)單繼承功能的類,意在重用其功能。在面向?qū)ο蟮恼Z言中,我們會(huì)通過接口繼承的方式來實(shí)現(xiàn)功能的復(fù)用。但是在javascript中,我們沒辦法通過接口繼承的方式,但是我們可以通過javascript特有的原型鏈屬性,將功能引用復(fù)制到原型鏈上,達(dá)到功能的注入。
示例下面通過一個(gè)簡(jiǎn)單的例子來演示這個(gè)模式
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") } } //混入模式的實(shí)現(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 //不指定特定方法名的時(shí)候,將后者所有的方法都添加到前者里 Merge(Car, Mixin) var mySportsCar = new Car({ model: "Porsche", color: "red" }) mySportsCar.driveForward() //drive forward優(yōu)缺點(diǎn)
優(yōu)點(diǎn)
有助于減少系統(tǒng)中的重復(fù)功能及增加函數(shù)復(fù)用。當(dāng)一個(gè)應(yīng)用程序可能需要在各種對(duì)象實(shí)例中共享行為時(shí),我們可以通過在Mixin中維持這種共享功能并專注于僅實(shí)現(xiàn)系統(tǒng)中真正不同的功能,來輕松避免任何重復(fù)。
缺點(diǎn)
有些人認(rèn)為將功能注入對(duì)象原型中會(huì)導(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的時(shí)候options._isComponent為false,會(huì)走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的實(shí)現(xiàn)src/core/util/options.js
mergeField將this.options(parent)和需要混入的對(duì)象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è)計(jì)模式》
JS設(shè)計(jì)模式系列文章JS設(shè)計(jì)模式之Obeserver(觀察者)模式、Publish/Subscribe(發(fā)布/訂閱)模式
JS設(shè)計(jì)模式之Factory(工廠)模式
JS設(shè)計(jì)模式之Singleton(單例)模式
JS設(shè)計(jì)模式之Facade(外觀)模式
JS設(shè)計(jì)模式之Module(模塊)模式、Revealing Module(揭示模塊)模式
JS設(shè)計(jì)模式之Mixin(混入)模式
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/103895.html
摘要:現(xiàn)在有一個(gè)需求,將沒有而有的屬性混入到中。有而且也有的屬性不混入以為準(zhǔn)。通過這種混入機(jī)制滾雪球的方式可以不斷地?cái)U(kuò)充一個(gè)對(duì)象地的功能。暫且將它定義為混入模式?;烊肽J绞菢?gòu)建復(fù)雜對(duì)象的一種常用的模式。 有A對(duì)象和B對(duì)象,A, B對(duì)象有有方法屬性和數(shù)據(jù)屬性?,F(xiàn)在有一個(gè)需求,將A沒有而B有的屬性混入到A中。A有而且B也有的屬性不混入以A為準(zhǔn)。通過這種混入機(jī)制(滾雪球的方式)可以不斷地?cái)U(kuò)充一個(gè)對(duì)...
摘要:使用替換目標(biāo)在第三篇文章中,我們使用來抽離了注入依賴項(xiàng)的公共邏輯。成果通過作用域插槽,我們有效地避免了第三方組件由于混入而可能造成的命名沖突以及隱式依賴等問題。 04 使用 slot 替換 mixin 目標(biāo) 在第三篇文章中,我們使用 mixin 來抽離了注入 toggle 依賴項(xiàng)的公共邏輯。在 react 中,類似的需求是通過 HOC 的方式來解決的,但是仔細(xì)想想的話,react 在早...
摘要:在中,我們是否也有一些手段或特性來提高組件的復(fù)用程度和靈活性呢答案當(dāng)然是有的,那就是。成果通過實(shí)現(xiàn),我們成功將注入的邏輯抽離了出來,這樣每次需要共享組件的狀態(tài)和方法時(shí),混入該即可。 03 使用 mixin 來增強(qiáng) Vue 組件 目標(biāo) 之前一篇文章中,我們雖然將 toggle 組件劃分為了 toggle-button、toggle-on 和 toggle-off 三個(gè)子組件,且一切運(yùn)行良...
摘要:前言最近開發(fā)的頁(yè)面以及功能大都以表格為主,接口獲取來的數(shù)據(jù)大都是需要經(jīng)過處理,比如時(shí)間戳需要轉(zhuǎn)換,或者狀態(tài)碼的轉(zhuǎn)義。首先,還是在文件中定義一個(gè)狀態(tài)碼對(duì)應(yīng)對(duì)象,這里我們將其對(duì)應(yīng)的內(nèi)容設(shè)為段落。 前言 最近開發(fā)的頁(yè)面以及功能大都以表格為主,接口獲取來的 JSON 數(shù)據(jù)大都是需要經(jīng)過處理,比如時(shí)間戳需要轉(zhuǎn)換,或者狀態(tài)碼的轉(zhuǎn)義。對(duì)于這樣的問題,各大主流框架都提供了類似于過濾的方法,在 Vue ...
閱讀 2344·2023-04-25 14:29
閱讀 1473·2021-11-22 09:34
閱讀 2714·2021-11-22 09:34
閱讀 3398·2021-11-11 10:59
閱讀 1863·2021-09-26 09:46
閱讀 2238·2021-09-22 16:03
閱讀 1928·2019-08-30 12:56
閱讀 484·2019-08-30 11:12