Klassen
Bevorzugen Sie ES2015/ES6-Klassen gegenüber ES5-Funktionen
Bei klassischen ES5-Klassen ist es äußerst schwierig, lesbare Klassenvererbung, Konstruktion und Methodendefinitionen zu erreichen. Wenn Sie Vererbung benötigen (bedenken Sie dabei, dass Sie sie möglicherweise nicht brauchen), sollten Sie ES2015/ES6-Klassen bevorzugen. Allerdings empfehlen wir zunächst kleinere Funktionen statt Klassen zu verwenden, bis Sie größere und komplexere Objekte benötigen.
Schlecht:
const Animal = function(age) {
if (!(this instanceof Animal)) {
throw new Error("Instantiate Animal with `new`");
}
this.age = age;
};
Animal.prototype.move = function move() {};
const Mammal = function(age, furColor) {
if (!(this instanceof Mammal)) {
throw new Error("Instantiate Mammal with `new`");
}
Animal.call(this, age);
this.furColor = furColor;
};
Mammal.prototype = Object.create(Animal.prototype);
Mammal.prototype.constructor = Mammal;
Mammal.prototype.liveBirth = function liveBirth() {};
const Human = function(age, furColor, languageSpoken) {
if (!(this instanceof Human)) {
throw new Error("Instantiate Human with `new`");
}
Mammal.call(this, age, furColor);
this.languageSpoken = languageSpoken;
};
Human.prototype = Object.create(Mammal.prototype);
Human.prototype.constructor = Human;
Human.prototype.speak = function speak() {};Gut:
class Animal {
constructor(age) {
this.age = age;
}
move() {
/* ... */
}
}
class Mammal extends Animal {
constructor(age, furColor) {
super(age);
this.furColor = furColor;
}
liveBirth() {
/* ... */
}
}
class Human extends Mammal {
constructor(age, furColor, languageSpoken) {
super(age, furColor);
this.languageSpoken = languageSpoken;
}
speak() {
/* ... */
}
}Verwenden Sie Methodenverkettung
Dieses Muster ist in JavaScript sehr nützlich und findet sich in Bibliotheken wie jQuery und Lodash. Es macht Code ausdrucksstärker und prägnanter. Daher empfehlen wir Methodenverkettung – achten Sie darauf, wie übersichtlich Ihr Code wird. In Ihren Klassenmethoden geben Sie einfach this am Ende jeder Funktion zurück, um weitere Methodenaufrufe anzuketten.
Schlecht:
class Car {
constructor(make, model, color) {
this.make = make;
this.model = model;
this.color = color;
}
setMake(make) {
this.make = make;
}
setModel(model) {
this.model = model;
}
setColor(color) {
this.color = color;
}
save() {
console.log(this.make, this.model, this.color);
}
}
const car = new Car("Ford", "F-150", "red");
car.setColor("pink");
car.save();Gut:
class Car {
constructor(make, model, color) {
this.make = make;
this.model = model;
this.color = color;
}
setMake(make) {
this.make = make;
// NOTE: Returning this for chaining
return this;
}
setModel(model) {
this.model = model;
// NOTE: Returning this for chaining
return this;
}
setColor(color) {
this.color = color;
// NOTE: Returning this for chaining
return this;
}
save() {
console.log(this.make, this.model, this.color);
// NOTE: Returning this for chaining
return this;
}
}
const car = new Car("Ford", "F-150", "red").setColor("pink").save();Bevorzugen Sie Komposition statt Vererbung
Wie in Design Patterns der „Gang of Four“ beschrieben, sollte Komposition wo möglich der Vererbung vorgezogen werden. Während beide Konzepte ihre Berechtigung haben, liegt die Kernaussage darin: Falls Sie intuitiv zu Vererbung tendieren, prüfen Sie stattdessen, ob Komposition das Problem besser abbilden kann. Dies ist häufig der Fall.
Sie fragen sich vielleicht: „Wann sollte ich dann Vererbung verwenden?“ Dies hängt vom konkreten Problem ab, aber folgende Kriterien können helfen:
- Die Vererbung repräsentiert eine „is-a“-Beziehung, keine „has-a“-Beziehung (Mensch->Tier vs. Benutzer->Benutzerdaten).
- Die Wiederverwendung von Code aus Basisklassen ist möglich (Menschen können sich wie alle Tiere bewegen).
- Sie möchten globale Änderungen an abgeleiteten Klassen vornehmen, indem Sie die Basisklasse modifizieren (z.B. Änderung des Kalorienverbrauchs aller Tiere bei Bewegung).
Schlecht:
class Employee {
constructor(name, email) {
this.name = name;
this.email = email;
}
// ...
}
// Bad because Employees "have" tax data. EmployeeTaxData is not a type of Employee
class EmployeeTaxData extends Employee {
constructor(ssn, salary) {
super();
this.ssn = ssn;
this.salary = salary;
}
// ...
}Gut:
class EmployeeTaxData {
constructor(ssn, salary) {
this.ssn = ssn;
this.salary = salary;
}
// ...
}
class Employee {
constructor(name, email) {
this.name = name;
this.email = email;
}
setTaxData(ssn, salary) {
this.taxData = new EmployeeTaxData(ssn, salary);
}
// ...
}