JavaScript 中的 Mixin
Javascript 默认不支持多重继承。但有时我们需要将多个对象的属性混合到单个对象中。可以使用 mixin 来实现对象属性共享。在本文中,我们将介绍 JavaScript 中的 mixin。
Mixin 的定义可以描述为:Mixin 是一个包含方法的类,其他类可以使用这些方法而无需继承该类。Mixin 中的方法提供某些行为,这些行为不会单独使用,但可以用来向其他类添加这些行为。
Mixin:一个简单的例子
请看下面的例子,我们有一个名为 DoodleHome 的智能家居设备和另一个名为 DoodleSpeak 的扬声器对象。DoodleSpeak 对象中已经定义了一些消息,这些消息在 DoodleHome 中被使用。
示例
<!DOCTYPE html> <html> <head> <title>HTML Console</title> </head> <body> <h3> Output Console </h3> <p> Output: </p> <div id="output"> </div> <div id="opError" style="color : #ff0000"> </div> <script> var content = '' var error = '' var opDiv = document.querySelector('#output') var opErrDiv = document.querySelector('#opError') // actual javascript code try { let DoodleSpeak = { doodleHello() { content += 'Hello! ' + this.name + "<br>"; }, doodleBye() { content += 'Good Bye! ' + this.name + "<br>"; }, }; class DoodleHome { constructor(name) { this.name = name; } } // copy the methods from Object.assign(DoodleHome.prototype, DoodleSpeak); doodly = new DoodleHome("Doodly"); mixi = new DoodleHome("Mixi") doodly.doodleHello(); mixi.doodleHello(); doodly.doodleBye(); mixi.doodleBye(); } catch (err) { error += err } finally { // display on output console opDiv.innerHTML = content opErrDiv.innerHTML = error } </script> </body> </html>
在这个例子中,DoodleHome 对象被赋值给另一个类 DoodleSpeak。这个赋值 () 方法在 mixin 中扮演着重要的角色。Mixin 可以在其内部使用继承。例如,如果我们创建一个 DoodleSay() 对象类型,并在 DoodleSpeak 中以更通用的形式实现它,那将是一个更好的实现。让我们看下面的例子来理解这个概念。
示例
<!DOCTYPE html> <html> <head> <title>HTML Console</title> </head> <body> <h3> Output Console </h3> <p> Output: </p> <div id="output"> </div> <div id="opError" style="color : #ff0000"> </div> <script> var content = '' var error = '' var opDiv = document.querySelector('#output') var opErrDiv = document.querySelector('#opError') // actual javascript code try { let DoodleSay = { saySomething(statement) { content += statement + "<br>"; } }; let DoodleSpeak = { __proto__: DoodleSay, doodleHello() { super.saySomething(`Hello! ${this.name}`); }, doodleBye() { super.saySomething(`Good Bye! ${this.name}`); }, }; class DoodleHome { constructor(name) { this.name = name; } } // copy the methods from DoodleSpeak Object.assign(DoodleHome.prototype, DoodleSpeak); doodly = new DoodleHome("Doodly"); mixi = new DoodleHome("Mixi") doodly.doodleHello(); mixi.doodleHello(); doodly.doodleBye(); mixi.doodleBye(); } catch (err) { error += err } finally { // display on output console opDiv.innerHTML = content opErrDiv.innerHTML = error } </script> </body> </html>
示例
让我们看另一个包含超类和类 mixin 的例子
<!DOCTYPE html> <html> <head> <title>HTML Console</title> </head> <body> <h3> Output Console </h3> <p> Output: </p> <div id="output"> </div> <div id="opError" style="color : #ff0000"> </div> <script> var content = '' var error = '' var opDiv = document.querySelector('#output') var opErrDiv = document.querySelector('#opError') // actual javascript code try { let DoodleSay = { saySomething(statement) { content += statement + "<br>"; } }; class Animal { constructor() { this._state = 'not moving, stays idle'; } get state() { return this._state; } } class Bird extends Animal { walk() { this._state = 'walking on ground'; } } function Flyer(parentClass) { return class extends parentClass { fly() { this._state = 'flying in the sky'; } } } function Swimmer(parentClass) { return class extends parentClass { swim() { this._state = 'swimming in water'; } } } class Crow extends Flyer(Bird) { } class Duck extends Swimmer(Flyer(Bird)) { } class Penguin extends Bird { } const crowObj = new Crow(); crowObj.fly(); content += 'State of the CROW: ' + JSON.stringify(crowObj.state) + "<br>"; const duckObj = new Duck(); duckObj.fly(); duckObj.swim(); content += 'State of the DUCK: ' + JSON.stringify(duckObj.state) + "<br>"; const penguinObj = new Penguin(); penguinObj.fly(); // Throws an error as the Penguin have no fly method } catch (err) { error += err } finally { // display on output console opDiv.innerHTML = content opErrDiv.innerHTML = error } </script> </body> </html>
在这个例子中,我们定义了一些类,例如 Animal 和 Bird,Bird 是 Animal 的子类。目前所有动物都是静止的,鸟类具有 walk 属性,以便所有鸟类都可以行走。Flyer 函数将创建一个类,该类接受一个父类类型,并将为其分配 fly() 属性,类似地,Swimmer 类将返回另一个具有 swim 属性的类类型。这些不同的类类型被合并到某些对象中。在这个例子中,Crow、Duck 和 Penguin 都是鸟类,但 swim 属性被分配给 Duck,Crow 和 Duck 也可以飞行,但 Penguin 没有 fly() 属性,所以它返回一个错误,指出:“TypeError: penguinObj.fly is not a function”
Mixin 的优点和缺点
在 JavaScript 中,Mixin 减少了系统中的功能重复和多个函数的重复使用。有时我们需要跨对象实例共享行为,我们可以通过在 Mixin 中维护此共享功能来轻松避免任何重复,从而专注于仅实现系统中真正需要且唯一的那些功能。
Mixin 的局限性有点令人困惑。一些开发者认为将功能注入对象原型不是一个好主意,因为它会在对象内部插入不必要的代码,并对函数的来源产生一定程度的不确定性。
结论
Javascript 不是一门完全面向对象的语言。因此,Javascript 不直接支持多重继承。我们可以使用 Mixin 的概念来实现将不同对象的属性复制到单个对象的效果。我们可以定义多个类或对象类型及其属性,然后使用 apply() 方法将它们从一个类合并到另一组类中。
数据结构
网络
关系数据库管理系统 (RDBMS)
操作系统
Java
iOS
HTML
CSS
Android
Python
C 编程
C++
C#
MongoDB
MySQL
Javascript
PHP