摘要:概念模式就是一些提供能夠被一個或者一組子類簡單繼承功能的類意在重用其功能。示例下面通過一個簡單的例子來演示這個模式混入模式的實現不指定特定方法名的時候,將后者所有的方法都添加到前者里優缺點優點有助于減少系統中的重復功能及增加函數復用。
概念
Mixin模式就是一些提供能夠被一個或者一組子類簡單繼承功能的類,意在重用其功能。在面向對象的語言中,我們會通過接口繼承的方式來實現功能的復用。但是在javascript中,我們沒辦法通過接口繼承的方式,但是我們可以通過javascript特有的原型鏈屬性,將功能引用復制到原型鏈上,達到功能的注入。
示例下面通過一個簡單的例子來演示這個模式
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") } } //混入模式的實現 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優缺點
優點
有助于減少系統中的重復功能及增加函數復用。當一個應用程序可能需要在各種對象實例中共享行為時,我們可以通過在Mixin中維持這種共享功能并專注于僅實現系統中真正不同的功能,來輕松避免任何重復。
缺點
有些人認為將功能注入對象原型中會導致原型污染和函數起源方面的不確定性。
vue中關于混入的代碼目錄/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 } }
下面我們來看合并配置的相關代碼/src/core/instance/init.js
當執行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的實現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設計模式》
JS設計模式系列文章JS設計模式之Obeserver(觀察者)模式、Publish/Subscribe(發布/訂閱)模式
JS設計模式之Factory(工廠)模式
JS設計模式之Singleton(單例)模式
JS設計模式之Facade(外觀)模式
JS設計模式之Module(模塊)模式、Revealing Module(揭示模塊)模式
JS設計模式之Mixin(混入)模式
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/103895.html
摘要:使用替換目標在第三篇文章中,我們使用來抽離了注入依賴項的公共邏輯。成果通過作用域插槽,我們有效地避免了第三方組件由于混入而可能造成的命名沖突以及隱式依賴等問題。 04 使用 slot 替換 mixin 目標 在第三篇文章中,我們使用 mixin 來抽離了注入 toggle 依賴項的公共邏輯。在 react 中,類似的需求是通過 HOC 的方式來解決的,但是仔細想想的話,react 在早...
摘要:在中,我們是否也有一些手段或特性來提高組件的復用程度和靈活性呢答案當然是有的,那就是。成果通過實現,我們成功將注入的邏輯抽離了出來,這樣每次需要共享組件的狀態和方法時,混入該即可。 03 使用 mixin 來增強 Vue 組件 目標 之前一篇文章中,我們雖然將 toggle 組件劃分為了 toggle-button、toggle-on 和 toggle-off 三個子組件,且一切運行良...
摘要:前言最近開發的頁面以及功能大都以表格為主,接口獲取來的數據大都是需要經過處理,比如時間戳需要轉換,或者狀態碼的轉義。首先,還是在文件中定義一個狀態碼對應對象,這里我們將其對應的內容設為段落。 前言 最近開發的頁面以及功能大都以表格為主,接口獲取來的 JSON 數據大都是需要經過處理,比如時間戳需要轉換,或者狀態碼的轉義。對于這樣的問題,各大主流框架都提供了類似于過濾的方法,在 Vue ...
閱讀 2335·2023-04-25 14:29
閱讀 1457·2021-11-22 09:34
閱讀 2702·2021-11-22 09:34
閱讀 3392·2021-11-11 10:59
閱讀 1851·2021-09-26 09:46
閱讀 2223·2021-09-22 16:03
閱讀 1921·2019-08-30 12:56
閱讀 479·2019-08-30 11:12