Klassen
Baseline Widely available
This feature is well established and works across many devices and browser versions. It’s been available across browsers since March 2017.
Klassen sind eine Vorlage zur Erstellung von Objekten. Sie kapseln Daten mit Code, um mit diesen Daten zu arbeiten. Klassen in JS basieren auf Prototypen, haben aber auch einige Syntax- und Semantikunterschiede, die einzigartig für Klassen sind.
Für weitere Beispiele und Erklärungen, siehe den Verwendung von Klassen-Leitfaden.
Beschreibung
Klassen definieren
Klassen sind in der Tat "spezielle Funktionen" und ebenso wie Sie Funktionsausdrücke und Funktionsdeklarationen definieren können, kann eine Klasse auf zwei Arten definiert werden: ein Klassen-Ausdruck oder eine Klassen-Deklaration.
// Declaration
class Rectangle {
constructor(height, width) {
this.height = height;
this.width = width;
}
}
// Expression; the class is anonymous but assigned to a variable
const Rectangle = class {
constructor(height, width) {
this.height = height;
this.width = width;
}
};
// Expression; the class has its own name
const Rectangle = class Rectangle2 {
constructor(height, width) {
this.height = height;
this.width = width;
}
};
Wie Funktionsausdrücke können Klassenausdrücke anonym sein oder einen Namen haben, der sich von dem unterscheidet, der der Variablen zugewiesen ist. Im Gegensatz zu Funktionsdeklarationen haben Klassendeklarationen jedoch die gleichen Einschränkungen der temporären Totzone wie let
oder const
und verhalten sich, als ob sie nicht gehoben werden.
Klassenkörper
Der Körper einer Klasse ist der Teil, der in geschweifte Klammern {}
eingeschlossen ist. Hier definieren Sie Klassenmitglieder wie Methoden oder Konstruktor.
Der Körper einer Klasse wird im strikten Modus ausgeführt, auch ohne die "use strict"
Direktive.
Ein Klassenelement kann durch drei Aspekte charakterisiert werden:
- Art: Getter, Setter, Methode oder Feld
- Ort: Statisch oder Instanz
- Sichtbarkeit: Öffentlich oder privat
Zusammen ergeben sie 16 mögliche Kombinationen. Um die Referenz logischer zu gliedern und überlappende Inhalte zu vermeiden, werden die verschiedenen Elemente ausführlich auf verschiedenen Seiten vorgestellt:
- Methodendefinitionen
-
Öffentliche Instanzmethode
- getter
-
Öffentlicher Instanz-Getter
- setter
-
Öffentlicher Instanz-Setter
- Öffentliche Klassenfelder
-
Öffentliches Instanzfeld
static
-
Öffentliche statische Methode, Getter, Setter und Feld
- Private Eigenschaften
-
Alles, was privat ist
Hinweis: Private Eigenschaften haben die Einschränkung, dass alle Eigenschaftsnamen, die in derselben Klasse deklariert sind, einzigartig sein müssen. Alle anderen öffentlichen Eigenschaften unterliegen dieser Einschränkung nicht — Sie können mehrere öffentliche Eigenschaften mit demselben Namen haben, und die letzte überschreibt die anderen. Dies ist dasselbe Verhalten wie bei Objektinitialisierern.
Darüber hinaus gibt es zwei spezielle Klassen-Elementsyntax: constructor
und statische Initialisierungsblöcke, mit ihren eigenen Referenzen.
Konstruktor
Die constructor
Methode ist eine spezielle Methode zur Erstellung und Initialisierung eines Objekts, das mit einer Klasse erstellt wurde. Es kann nur eine spezielle Methode mit dem Namen "constructor" in einer Klasse geben — ein SyntaxError
wird ausgelöst, wenn die Klasse mehr als eine Vorkommen einer constructor
Methode enthält.
Ein Konstruktor kann das super
Schlüsselwort verwenden, um den Konstruktor der Superklasse aufzurufen.
Sie können Instanzeigenschaften innerhalb des Konstruktors erstellen:
class Rectangle {
constructor(height, width) {
this.height = height;
this.width = width;
}
}
Alternativ, wenn die Werte Ihrer Instanzeigenschaften nicht von den Argumenten des Konstruktors abhängen, können Sie sie als Klassenfelder definieren.
Statische Initialisierungsblöcke
Statische Initialisierungsblöcke erlauben flexible Initialisierung von statischen Eigenschaften, einschließlich der Auswertung von Anweisungen während der Initialisierung, während sie Zugang zum privaten Bereich gewähren.
Mehrere statische Blöcke können deklariert werden, und diese können mit der Deklaration von statischen Feldern und Methoden durchmischt werden (alle statischen Elemente werden in Deklarationsreihenfolge ausgewertet).
Methoden
Methoden werden im Prototyp jeder Instanz einer Klasse definiert und von allen Instanzen gemeinsam genutzt. Methoden können einfache Funktionen, asynchrone Funktionen, Generatorfunktionen oder asynchrone Generatorfunktionen sein. Für mehr Informationen, siehe Methodendefinitionen.
class Rectangle {
constructor(height, width) {
this.height = height;
this.width = width;
}
// Getter
get area() {
return this.calcArea();
}
// Method
calcArea() {
return this.height * this.width;
}
*getSides() {
yield this.height;
yield this.width;
yield this.height;
yield this.width;
}
}
const square = new Rectangle(10, 10);
console.log(square.area); // 100
console.log([...square.getSides()]); // [10, 10, 10, 10]
Statische Methoden und Felder
Das static
Schlüsselwort definiert eine statische Methode oder ein statisches Feld für eine Klasse. Statische Eigenschaften (Felder und Methoden) werden an der Klasse selbst statt bei jeder Instanz definiert. Statische Methoden werden oft genutzt, um Hilfsfunktionen für eine Anwendung zu erstellen, während statische Felder für Caches, feste Konfigurationen oder andere Daten nützlich sind, die nicht für jede Instanz repliziert werden müssen.
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
static displayName = "Point";
static distance(a, b) {
const dx = a.x - b.x;
const dy = a.y - b.y;
return Math.hypot(dx, dy);
}
}
const p1 = new Point(5, 5);
const p2 = new Point(10, 10);
p1.displayName; // undefined
p1.distance; // undefined
p2.displayName; // undefined
p2.distance; // undefined
console.log(Point.displayName); // "Point"
console.log(Point.distance(p1, p2)); // 7.0710678118654755
Felddeklarationen
Mit der Klassenfelddeklarationssyntax kann das Konstruktor Beispiel wie folgt geschrieben werden:
class Rectangle {
height = 0;
width;
constructor(height, width) {
this.height = height;
this.width = width;
}
}
Klassenfelder sind ähnlich wie Objekteigenschaften, nicht wie Variablen, sodass wir keine Schlüsselwörter wie const
verwenden, um sie zu deklarieren. In JavaScript verwenden private Eigenschaften eine spezielle Identifikatursyntax, deshalb sollten auch keine Modifikatorschlüsselwörter wie public
und private
verwendet werden.
Wie oben gezeigt, können die Felder mit oder ohne einen Standardwert deklariert werden. Felder ohne Standardwerte haben per Standard undefined
. Durch die Deklaration von Feldern im Voraus werden Klassendefinitionen selbstdokumentierender, und die Felder sind immer vorhanden, was bei Optimierungen hilft.
Siehe öffentliche Klassenfelder für mehr Informationen.
Private Eigenschaften
Mit privaten Feldern kann die Definition wie folgt verfeinert werden.
class Rectangle {
#height = 0;
#width;
constructor(height, width) {
this.#height = height;
this.#width = width;
}
}
Es ist ein Fehler, auf private Felder von außerhalb der Klasse zuzugreifen; sie können nur innerhalb des Klassenkörpers gelesen oder geschrieben werden. Indem Sie Dinge definieren, die außerhalb der Klasse nicht sichtbar sind, stellen Sie sicher, dass Benutzer Ihrer Klassen nicht von internen Details abhängig sind, die sich von Version zu Version ändern könnten.
Private Felder können nur im Voraus in einer Felddeklaration deklariert werden. Sie können nicht später durch Zuweisung zu ihnen erstellt werden, wie es bei normalen Eigenschaften der Fall ist.
Für mehr Informationen, siehe private Eigenschaften.
Vererbung
Das extends
Schlüsselwort wird in Klassendeklarationen oder Klassen-Ausdrücken verwendet, um eine Klasse als Kind eines anderen Konstruktors (entweder einer Klasse oder einer Funktion) zu erstellen.
class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(`${this.name} makes a noise.`);
}
}
class Dog extends Animal {
constructor(name) {
super(name); // call the super class constructor and pass in the name parameter
}
speak() {
console.log(`${this.name} barks.`);
}
}
const d = new Dog("Mitzie");
d.speak(); // Mitzie barks.
Wenn im Unterklasse ein Konstruktor vorhanden ist, muss er zunächst super()
aufrufen, bevor this
verwendet wird. Das super
Schlüsselwort kann auch verwendet werden, um entsprechende Methoden der Superklasse aufzurufen.
class Cat {
constructor(name) {
this.name = name;
}
speak() {
console.log(`${this.name} makes a noise.`);
}
}
class Lion extends Cat {
speak() {
super.speak();
console.log(`${this.name} roars.`);
}
}
const l = new Lion("Fuzzy");
l.speak();
// Fuzzy makes a noise.
// Fuzzy roars.
Auswertungsreihenfolge
Wenn eine class
Deklaration oder ein class
Ausdruck ausgewertet wird, werden seine verschiedenen Komponenten in der folgenden Reihenfolge ausgewertet:
- Der
extends
Satz, wenn vorhanden, wird zuerst ausgewertet. Er muss zu einer gültigen Konstruktorfunktion odernull
ausgewertet werden, oder einTypeError
wird ausgelöst. - Die
constructor
Methode wird extrahiert, durch eine Standardimplementierung ersetzt, fallsconstructor
nicht vorhanden ist. Da dieconstructor
Definition jedoch nur eine Methodendefinition ist, ist dieser Schritt nicht beobachtbar. - Die Schlüsseln der Klassenelemente werden in der Reihenfolge der Deklaration ausgewertet. Wenn der Schlüssel berechnet wird, wird der berechnete Ausdruck ausgewertet, wobei der
this
Wert auf denthis
Wert im umgebenden Kontext der Klasse (nicht die Klasse selbst) gesetzt wird. Keiner der Eigenschaftswerte wird zu diesem Zeitpunkt ausgewertet. - Methoden und Zugriffsrechte werden in der Reihenfolge der Deklaration installiert. Instanzmethoden und Zugriffsmethoden werden im
prototype
der aktuellen Klasse installiert, und statische Methoden und Zugriffsmethoden werden in der Klasse selbst installiert. Private Instanzmethoden und Zugriffsmethoden werden gespeichert, um später direkt auf der Instanz installiert zu werden. Dieser Schritt ist nicht beobachtbar. - Die Klasse ist jetzt mit dem durch
extends
spezifizierten Prototyp und der durchconstructor
spezifizierten Implementierung initialisiert. Für alle oben genannten Schritte, wenn ein ausgewerteter Ausdruck versucht, auf den Namen der Klasse zuzugreifen, wird einReferenceError
ausgelöst, da die Klasse noch nicht initialisiert ist. - Die Werte der Klassenelemente werden in der Reihenfolge der Deklaration ausgewertet:
- Für jedes Instanzfeld (öffentlich oder privat) wird der Initialisierungs-Ausdruck gespeichert. Der Initialisierer wird während der Erstellung der Instanz ausgewertet, zu Beginn des Konstruktors (für Basisklassen) oder unmittelbar bevor der
super()
-Aufruf zurückkehrt (für abgeleitete Klassen). - Für jedes statische Feld (öffentlich oder privat) wird der Initialisierer mit
this
auf die Klasse selbst gesetzt ausgewertet und die Eigenschaft auf der Klasse erstellt. - Statische Initialisierungsblöcke werden mit
this
auf die Klasse selbst gesetzt ausgewertet.
- Für jedes Instanzfeld (öffentlich oder privat) wird der Initialisierungs-Ausdruck gespeichert. Der Initialisierer wird während der Erstellung der Instanz ausgewertet, zu Beginn des Konstruktors (für Basisklassen) oder unmittelbar bevor der
- Die Klasse ist jetzt vollständig initialisiert und kann als Konstruktorfunktion verwendet werden.
Wie Instanzen erstellt werden, siehe die constructor
-Referenz.
Beispiele
Binding von this mit Instanz- und statischen Methoden
Wenn eine statische oder Instanzmethode ohne einen Wert für this
aufgerufen wird, wie z. B. durch Zuweisung der Methode zu einer Variablen und sie dann aufzurufen, wird der this
Wert innerhalb der Methode undefined
sein. Dieses Verhalten ist dasselbe, auch wenn die "use strict"
Direktive nicht vorhanden ist, da Code im class
Körper immer im strikten Modus ausgeführt wird.
class Animal {
speak() {
return this;
}
static eat() {
return this;
}
}
const obj = new Animal();
obj.speak(); // the Animal object
const speak = obj.speak;
speak(); // undefined
Animal.eat(); // class Animal
const eat = Animal.eat;
eat(); // undefined
Wenn wir das Obige unter Verwendung der traditionellen, auf Funktionen basierenden Syntax im nicht-strikten Modus umschreiben, dann werden this
-Methodenaufrufe automatisch an globalThis
gebunden. Im strikten Modus bleibt der Wert von this
jedoch undefined
.
function Animal() {}
Animal.prototype.speak = function () {
return this;
};
Animal.eat = function () {
return this;
};
const obj = new Animal();
const speak = obj.speak;
speak(); // global object (in non–strict mode)
const eat = Animal.eat;
eat(); // global object (in non-strict mode)
Spezifikationen
Specification |
---|
ECMAScript Language Specification # sec-class-definitions |
Browser-Kompatibilität
BCD tables only load in the browser
Siehe auch
- Verwendung von Klassen Leitfaden
class
class
Ausdruck- Funktionen
- ES6 In Depth: Classes auf hacks.mozilla.org (2015)