摘要:源码地址什么是一般翻译为混入混合,早期一般解释为把一个对象的方法和属性拷贝到另一个对象上也可以简单理解为能够被继承的类,最终目的是实现代码的复用。
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是一种思想,用来实现代码高度可复用性,又可以用来解决多继承的问题,是一种非常灵活的设计模式,如果你多多琢磨,相信你也会发现一些其他的妙用的,看好你哟!
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/95713.html
摘要:一般的做法是把这些动作写在和的两个方法里,单元测试框架会负责在开始和结束的时候调用这两个方法。从视觉上无法直观的指导原来和是一对的。然后再把这个小的上下文附着到主测试逻辑上这里利用了单元测试的的特性,把转化为回调在的时候就设置好。 很多测试都需要在启动的时候做一些事情,然后在结束的时候再把做的事情给清理了。一般的做法是把这些动作写在setUp和tearDown的两个方法里,单元测试框架...
摘要:最近新开了一个项目,采用来开发,在数据库及路由管理方面用了不少的装饰器,发觉这的确是一个好东西。在中的使用该装饰器会在定义前调用,如果函数有返回值,则会认为是一个新的构造函数来替代之前的构造函数。函数参数装饰器最后,还有一个用于函数参 最近新开了一个Node项目,采用TypeScript来开发,在数据库及路由管理方面用了不少的装饰器,发觉这的确是一个好东西。 装饰器是一个还处于草案中...
摘要:想要使用语法的话,配合,这个插件,体验更佳,这个插件在语法中实现了。这种方式最接近的单文件组件的写法,如果一个完善项目从改成,用这种方法很快,只要加上和一些必要的变量类型就好了,然后用包裹就好。不推荐混入用这种方式写,无法实现多继承。 最近尝试了一下 TypeScript,试着把一个 Vue 项目改成了 TypeScript 的,感觉还不错 目前 Vue 和 TypeScript 的配...
摘要:在下实现圆角效果由于兼容性特别差,所以要在低版本浏览器下实现圆周角效果特别难利用的效果可实现如下图所示的圆效果代码简单如下制作三杠效果其实就是利用特性变色我们在做如下图标时,一般情况下时会有三处变色但是利用继承自这一特性 在ie下实现圆角效果 (由于border-radius兼容性特别差,所以要在ie低版本浏览器下实现圆周角效果特别难)利用border-style的dotted效果可实...
阅读 2007·2021-11-18 10:02
阅读 2831·2021-09-04 16:41
阅读 1129·2019-08-30 15:55
阅读 1338·2019-08-29 17:27
阅读 1032·2019-08-29 17:12
阅读 2459·2019-08-29 15:38
阅读 2837·2019-08-29 13:02
阅读 2759·2019-08-29 12:29