摘要:源碼地址什么是一般翻譯為混入混合,早期一般解釋為把一個對象的方法和屬性拷貝到另一個對象上也可以簡單理解為能夠被繼承的類,最終目的是實現代碼的復用。
Github 源碼地址
什么是mixinmixin一般翻譯為“混入”、“混合”,
早期一般解釋為:把一個對象的方法和屬性拷貝到另一個對象上;
也可以簡單理解為能夠被繼承的類,
最終目的是實現代碼的復用。
為了使你能夠最快的清楚我在說什么,我們從一個需求說起:
一個項目中有多個彈層需求;
一些是公共方法,比如點擊關閉按鈕關閉彈層;
一些彈層是可以拖動的,且有蒙層;
一些彈層是可以縮放的;
其他都是業務方法,無可復用性。
你可以先在心里想下,如果是你,你會怎樣完成這個需求?
腦海中規劃下我們為公共方法寫個類:BaseModal
為可拖動的彈層寫個類:DragModal
為可縮放的彈層寫個類:ScaleModal
為自定義的業務需求寫個類:CustomModal
畫個腦圖的話,會是下面圖片中的樣子:
extends簡單實現下 看代碼// 公共方法 class BaseModal { close(){ console.log("close"); } } // 可以拖動的彈層,我們寫一個多帶帶的類 class DragModal extends BaseModal { hasLayer = true; drag() { console.log("drag"); } } // 可以縮放的彈層,我們寫一個多帶帶的類 class ScaleModal extends BaseModal { scale() { console.log("scale"); } } // 業務方法 class CustomModal extends DragModal { close(){ console.log("custom-close"); } do() { console.log("do"); } } let c = new CustomModal(); c.close(); // custom-close c.drag(); // drag c.do(); // do c.hasLayer; // true拋出問題
如何使CustomModal能夠同時繼承DragModal和ScaleModal?
某個相同方法希望不覆蓋,而是都執行
試試早期的mixin方法實現多繼承 看代碼// 可以拖動的彈層,我們寫一個多帶帶的類 class DragModal extends BaseModal { hasLayer = true; drag() { console.log("drag"); } } // 可以縮放的彈層,我們寫一個多帶帶的類 class ScaleModal extends BaseModal { scale() { console.log("scale"); } } // 獲取原型對象的所有屬性和方法 function getPrototypes(ClassPrototype) { return Object.getOwnPropertyNames(ClassPrototype).slice(1); } function mix(...mixins){ return function(target){ if (!mixins || !Array.isArray(mixins)) return target; let cp = target.prototype; for (let C of mixins) { let mp = C.prototype; for (let m of getPrototypes(mp)) { cp[m] = mp[m]; } } } } @mix(DragModal, ScaleModal) class CustomModal { scale(){ console.log("custom-scale"); } do() { console.log("do"); } } let c = new CustomModal(); c.close(); // 報錯,因為dobase沒在A或B的prototype上,而是在A.prototype.__proto__上 c.drag(); // drag c.scale(); // scale 并非是我們想要的custom-scale console.log(c.hasLayer); // undefined存在的問題
以上mix方式實現了多繼承,但存在以下問題
會修改target類的原型對象
target類的相同方法名會被被繼承類的相同方法名覆蓋
實例屬性無法繼承
BaseModal類無法被繼承
只繼承不修改prototype的實現方式 看代碼class BaseModal { close() { console.log("close"); } } let DragModalMixin = (extendsClass) => class extends extendsClass { hasLayer = true; drag() { console.log("drag"); } }; class CustomModal extends DragModalMixin(BaseModal) { drag() { console.log("custom-drag"); } do() { console.log("do"); } } let c = new CustomModal(); c.close(); // close c.drag(); // custom-drag console.log(c.hasLayer); // true存在的問題
如何讓CustomModal再繼承ScaleModal呢?
其實很簡單,在上面基礎上,我們再寫一個ScaleModalMixinMixin類就可以了
class BaseModal { close() { console.log("close"); } } let DragModalMixin = (extendsClass) => class extends extendsClass { hasLayer = true; drag() { console.log("drag"); } }; let ScaleModalMixin = (extendsClass) => class extends extendsClass { scale() { console.log("scale"); } }; class CustomModal extends ScaleModalMixin(DragModalMixin(BaseModal)) { drag() { console.log("custom-drag"); } do() { console.log("do"); } } let c = new CustomModal(); c.close(); // close c.drag(); // custom-drag c.scale(); // scale console.log(c.hasLayer); // true存在的問題
這種方式不會修改父類的原型對象,但是如果存在跟父類同名的方法,只會執行父類的,而不回執行被繼承的類的方法,那么如何使相同方法分別執行呢?
super實現相同方法不覆蓋 看代碼class BaseModal { close() { console.log("close"); } } let DragModalMixin = (extendsClass) => class extends extendsClass { hasLayer = true; drag() { console.log("drag"); } }; let ScaleModalMixin = (extendsClass) => class extends extendsClass { scale() { console.log("scale"); } close() { console.log("scale-close"); if (super.close) super.close(); } }; class CustomModal extends ScaleModalMixin(DragModalMixin(BaseModal)) { close() { console.log("custom-close"); if (super.close) super.close(); } do() { console.log("do"); } } let c = new CustomModal(); c.close(); // custom-close -> scale-close -> close總結
Mixin是一種思想,用來實現代碼高度可復用性,又可以用來解決多繼承的問題,是一種非常靈活的設計模式,如果你多多琢磨,相信你也會發現一些其他的妙用的,看好你喲!
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/95713.html
摘要:一般的做法是把這些動作寫在和的兩個方法里,單元測試框架會負責在開始和結束的時候調用這兩個方法。從視覺上無法直觀的指導原來和是一對的。然后再把這個小的上下文附著到主測試邏輯上這里利用了單元測試的的特性,把轉化為回調在的時候就設置好。 很多測試都需要在啟動的時候做一些事情,然后在結束的時候再把做的事情給清理了。一般的做法是把這些動作寫在setUp和tearDown的兩個方法里,單元測試框架...
摘要:最近新開了一個項目,采用來開發,在數據庫及路由管理方面用了不少的裝飾器,發覺這的確是一個好東西。在中的使用該裝飾器會在定義前調用,如果函數有返回值,則會認為是一個新的構造函數來替代之前的構造函數。函數參數裝飾器最后,還有一個用于函數參 最近新開了一個Node項目,采用TypeScript來開發,在數據庫及路由管理方面用了不少的裝飾器,發覺這的確是一個好東西。 裝飾器是一個還處于草案中...
摘要:想要使用語法的話,配合,這個插件,體驗更佳,這個插件在語法中實現了。這種方式最接近的單文件組件的寫法,如果一個完善項目從改成,用這種方法很快,只要加上和一些必要的變量類型就好了,然后用包裹就好。不推薦混入用這種方式寫,無法實現多繼承。 最近嘗試了一下 TypeScript,試著把一個 Vue 項目改成了 TypeScript 的,感覺還不錯 目前 Vue 和 TypeScript 的配...
摘要:在下實現圓角效果由于兼容性特別差,所以要在低版本瀏覽器下實現圓周角效果特別難利用的效果可實現如下圖所示的圓效果代碼簡單如下制作三杠效果其實就是利用特性變色我們在做如下圖標時,一般情況下時會有三處變色但是利用繼承自這一特性 在ie下實現圓角效果 (由于border-radius兼容性特別差,所以要在ie低版本瀏覽器下實現圓周角效果特別難)利用border-style的dotted效果可實...
閱讀 2101·2021-11-18 10:02
閱讀 2850·2021-09-04 16:41
閱讀 1142·2019-08-30 15:55
閱讀 1405·2019-08-29 17:27
閱讀 1070·2019-08-29 17:12
閱讀 2535·2019-08-29 15:38
閱讀 2855·2019-08-29 13:02
閱讀 2831·2019-08-29 12:29