Traits in Javascript [geschlossen]
-
22-09-2019 - |
Frage
Wie kann ich Züge in JavaScript implementieren?
Lösung
function Trait (methods) {
this.traits = [methods];
};
Trait.prototype = {
constructor: Trait
, uses: function (trait) {
this.traits = this.traits.concat (trait.traits);
return this;
}
, useBy: function (obj) {
for (var i = 0; i < this.traits.length; ++i) {
var methods = this.traits [i];
for (var prop in methods) {
if (methods.hasOwnProperty (prop)) {
obj [prop] = obj [prop] || methods [prop];
}
}
}
}
};
Trait.unimplemented = function (obj, traitName) {
if (obj === undefined || traitName === undefined) {
throw new Error ("Unimplemented trait property.");
}
throw new Error (traitName + " is not implemented for " + obj);
};
Beispiel:
var TEq = new Trait ({
equalTo: function (x) {
Trait.unimplemented (this, "equalTo");
}
, notEqualTo: function (x) {
return !this.equalTo (x);
}
});
var TOrd = new Trait ({
lessThan: function (x) {
Trait.unimplemented (this, "lessThan");
}
, greaterThan: function (x) {
return !this.lessThanOrEqualTo (x);
}
, lessThanOrEqualTo: function (x) {
return this.lessThan (x) || this.equalTo (x);
}
, greaterThanOrEqualTo: function (x) {
return !this.lessThan (x);
}
}).uses (TEq);
function Rational (numerator, denominator) {
if (denominator < 0) {
numerator *= -1;
denominator *= -1;
}
this.numerator = numerator;
this.denominator = denominator;
}
Rational.prototype = {
constructor: Rational
, equalTo: function (q) {
return this.numerator * q.numerator === this.denominator * q.denominator;
}
, lessThan: function (q) {
return this.numerator * q.denominator < q.numerator * this.denominator;
}
};
TOrd.useBy (Rational.prototype);
var x = new Rational (1, 5);
var y = new Rational (1, 2);
[x.notEqualTo (y), x.lessThan (y)]; // [true, true]
Andere Tipps
Es gibt verschiedene Ansätze und in der Zwischenzeit der Produktion bereit Bibliotheken als auch.
Mixins sind die älteste Form der Wiederverwendung von Code über Klassenhierarchien. Sie müssen in linearer Reihenfolge zusammengesetzt werden, da das Konzept des Mixins nicht Abdeckung / erkennt Konfliktlösung Funktionalität.
Traits sind feinkörnig Einheiten der Wiederverwendung von Code, dass die Arbeit auf Klassenebene zu; aber sie sind flexibler, da Traits Zusammensetzung Operatoren für die Kombination, Ausschluss oder Aliasing von Methoden zur Verfügung stellen müssen.
Ich empfehle zwei Papiere zu lesen sowohl eine Bibliothek Agnostiker reine Funktion basierte Konzept zu begegnen, sind für Mixins / Traits / Talent.
- Ein neuer Blick auf JavaScript Mixins von Angus Croll ab Mai 2011
- Die vielen Talente JavaScript für die Programmierung verallgemeinern Rollenorientierte Ansätze wie Traits und Mixins ab April 2014.
Die reine Funktion und Delegation basierte mixin Mechanik ist so einfach wie mit den nächsten 2 angegebenen Beispielen zur Verfügung gestellt ...
var Enumerable_first = function () {
this.first = function () {
return this[0];
};
};
var list = ["foo", "bar", "baz"];
console.log("(typeof list.first)", (typeof list.first)); // "undefined"
Enumerable_first.call(list); // explicit delegation
console.log("list.first()", list.first()); // "foo"
... mit dem ersten Beispiel auf "instance" Ebene wirkt, und die zweite Abdeckung "class" level ...
var Enumerable_first_last = function () {
this.first = function () {
return this[0];
};
this.last = function () {
return this[this.length - 1];
};
};
console.log("(typeof list.first)", (typeof list.first)); // "function" // as expected
console.log("(typeof list.last)", (typeof list.last)); // "undefined" // of course
Enumerable_first_last.call(Array.prototype); // applying behavior to [Array.prototype]
console.log("list.last()", list.last()); // "baz" // due to delegation automatism
Wenn man in Not ist für etablierte und / oder Produktion bereit Bibliotheken sollte man auf einen genaueren Blick
so lange
Anhang I
siehe auch:
- stackoverflow.com :: Wie Mixins richtig in Javascript verwenden
- stackoverflow.com :: Javascript Traits Pattern Ressourcen
Anhang II
Da von Zeit zu Zeit bin ich anscheinend Geige mit dieser Angelegenheit ich wan't ein paar letzte Gedanken, um es hinzuzufügen ...
Die Bibliothek agnostischer Ansatz ohne zu viel Kleber-Code (wie oben erwähnt) funktioniert nur für sehr feinkörnig zusammensetzbaren Einheiten von Verhalten Wiederverwendung. Somit kann, wie lange man läuft nicht in mehr als 1 oder 2 leicht auflösbaren Konflikte, Mustern, basierend auf z.B. Angus Croll von Flight Mixins ist der Weg zu folgen.
Wenn es um reale Züge kommt, muss da es sich um eine Abstraktionsebene sein. Diese Schicht (zum Beispiel als eine Art syntaktischen Zuckers wie ein DSL zur Verfügung gestellt) muss die Komplexität zum Beispiel verbergen von Merkmalen aus Züge oder der Konfliktlösung auf einen Züge gelten Zeit (wenn ein Merkmal, das Verhalten auf ein Objekt / Typ angewendet wird).
KomponierenMittlerweile gibt es drei Beispiele an, so dass aus meiner Sicht genau das, was die OP fragte ...
Wie kann ich Züge in JavaScript implementieren?
- stackoverflow.com :: Kompositionen und Mixins in JS
- stackoverflow.com :: Mixins für ES6 Klassen, transpiled mit babel
- stackoverflow.com :: Refactoring Vermächtnis mixin-basierte Klassenhierarchien
- stackoverflow.com :: Mehrfachvererbung mit Klassen
Ich empfehle Ihnen, ernsthaft die trait.js Bibliothek zur Kasse. Sie haben auch einen recht guten Artikel über das allgemeine Muster sowie deren konkrete Umsetzung. Ich habe vor kurzem in in mein Projekt gebaut und es funktioniert wie ein Charme.