使用JavaScript混合
当涉及到高级类组合时,JavaScript 有很多方法——真正的选项大杂烩。 一种很少在野外发现的模式是基于 mixin 的继承模式。 新的 JavaScript 程序员通常会跳过 Mixin(我也这样做过)。 我不想抱怨,但 mixins 有时会非常难以编写和理解。 但是它们具有许多值得研究的功能。
顾名思义,mixin 模式是一种将一个对象与其他对象混合在一起以添加我们需要的属性的模式。 可以把它想象成可以为您的对象提供额外属性的附加组件,但这些单独的属性本身并不是真正的子类。
从表面上看,mixin 的行为类似于对象混合层,我们在其中传入目标(mixin)和源。 目标附加到源并返回一个新对象。
更准确的描述是,mixin 作为工厂工作,返回新的子类对象。 在整个过程中,任何地方都没有子类的定义。
一个更 C++ 的类比是将它们与具有虚函数的抽象类进行比较,从而允许它们被其他子类继承。
所以,既然我们知道 mixin 允许我们创建一个修改后的定义,该定义可以应用于现有的超类以创建新的子类,让我们看看 mixin 的样子:
//The swim property here is the mixin let swim = { location() { console.log(`Heading ${this.direction} at ${this.speed}`); } }; let Alligator = function(speed, direction) { this.speed = speed, this.direction = direction }; //This is our source object let alligator = new Alligator('20 mph','North'); alligator = Object.assign(alligator, swim); console.log(alligator.location());
在上面的代码片段中,我们想要创建一个会游泳的鳄鱼。 所以我们创建一个新的 alligator
,然后给它 swim
特征。 swim
对象是我们希望 alligator
对象使用 Object.assign 方法 拥有的 mixin 或扩展。
Object.assign
方法允许我们一次添加多个 mixin。 多个 mixin 案例如下所示:
alligator = Object.assign(alligator, swim, crawl);
现在让我们看看 mixins 如何与 ES6 类 一起使用:
let swim = { setSwimProperties(speed, direction) { this.speed = speed; this.direction = direction; }, getSwimProperties(){ console.log(`swimming ${this.speed} towards ${this.direction}`); } } class Reptile { constructor(name) { this.name = name; } } Object.assign(Reptile.prototype, swim); let alligator = new Reptile("alligator"); alligator.setSwimProperties("5 m/s", "upstream"); alligator.getSwimProperties();
通过 mixin 方法添加功能的优点是灵活性。 mixin 是一个非常原始的函数,因为它只做一件事,允许我们在各种场景中重复使用这些结构。 它可以与本机函数调用一起使用,用于类定义等。
另一个好处是它倾向于保持类层次结构水平 - 通过允许超类使用混合来创建具有所需子类属性的新对象,而不是使继承链更长以便为这些情况创建新的子类。
使用 mixins 时要记住一些事情:
Object.assign
(在对象和类实现中)仅对 mixin 属性进行浅拷贝。- 使用来自不同 mixin 的属性时可能会出现名称冲突(多重继承中的菱形问题)
- 很难确定属性来自哪个 mixin,因为属性被复制到源对象上。 instanceof 运算符 在这里帮不了我们。