Öffentliche und private Klassenfelder
Mehrere Vorschläge erweitern die bestehende JavaScript-Klassensyntax um neue Funktionen. Dieser Artikel erklärt die neue Syntax von öffentlichen Klassenfeldern in V8 v7.2 und Chrome 72 sowie die kommende Syntax von privaten Klassenfeldern.
Hier ist ein Codebeispiel, das eine Instanz einer Klasse namens IncreasingCounter
erstellt:
const counter = new IncreasingCounter();
counter.value;
// protokolliert 'Den aktuellen Wert abrufen!'
// → 0
counter.increment();
counter.value;
// protokolliert 'Den aktuellen Wert abrufen!'
// → 1
Beachten Sie, dass der Zugriff auf value
einen Code ausführt (d. h., er protokolliert eine Nachricht), bevor das Ergebnis zurückgegeben wird. Überlegen Sie sich nun, wie Sie diese Klasse in JavaScript implementieren würden? 🤔
ES2015-Klassensyntax
So könnte IncreasingCounter
unter Verwendung der ES2015-Klassensyntax implementiert werden:
class IncreasingCounter {
constructor() {
this._count = 0;
}
get value() {
console.log('Den aktuellen Wert abrufen!');
return this._count;
}
increment() {
this._count++;
}
}
Die Klasse installiert den value
-Getter und eine increment
-Methode auf dem Prototyp. Interessanterweise hat die Klasse einen Konstruktor, der eine Instanzeigenschaft _count
erstellt und ihren Standardwert auf 0
setzt. Derzeit verwenden wir oft das Unterstrichpräfix, um anzuzeigen, dass _count
nicht direkt von Konsumenten der Klasse verwendet werden sollte, aber das ist nur eine Konvention; es ist keine wirklich „private“ Eigenschaft mit speziellen Semantiken, die von der Sprache durchgesetzt werden.
const counter = new IncreasingCounter();
counter.value;
// protokolliert 'Den aktuellen Wert abrufen!'
// → 0
// Nichts hindert die Leute daran, die
// Instanzeigenschaft `_count` zu lesen oder zu manipulieren. 😢
counter._count;
// → 0
counter._count = 42;
counter.value;
// protokolliert 'Den aktuellen Wert abrufen!'
// → 42
Öffentliche Klassenfelder
Die neue Syntax für öffentliche Klassenfelder erlaubt es uns, die Klassendefinition zu vereinfachen:
class IncreasingCounter {
_count = 0;
get value() {
console.log('Den aktuellen Wert abrufen!');
return this._count;
}
increment() {
this._count++;
}
}
Die _count
-Eigenschaft wird jetzt schön oben in der Klasse deklariert. Wir brauchen keinen Konstruktor mehr, nur um einige Felder zu definieren. Praktisch!
Die _count
-Eigenschaft ist jedoch immer noch eine öffentliche Eigenschaft. In diesem speziellen Beispiel möchten wir verhindern, dass Personen direkt auf die Eigenschaft zugreifen.
Private Klassenfelder
Hier kommen die privaten Klassenfelder ins Spiel. Die neue Syntax für private Felder ähnelt öffentlichen Feldern, außer dass sie das Feld als privat kennzeichnen, indem Sie #
verwenden. Sie können das #
als Teil des Feldnamens betrachten:
class IncreasingCounter {
#count = 0;
get value() {
console.log('Den aktuellen Wert abrufen!');
return this.#count;
}
increment() {
this.#count++;
}
}
Private Felder sind außerhalb des Klassenkörpers nicht zugänglich:
const counter = new IncreasingCounter();
counter.#count;
// → SyntaxError
counter.#count = 42;
// → SyntaxError
Öffentliche und private statische Eigenschaften
Die Syntax von Klassenfeldern kann auch verwendet werden, um öffentliche und private statische Eigenschaften und Methoden zu erstellen:
class FakeMath {
// `PI` ist eine statische öffentliche Eigenschaft.
static PI = 22 / 7; // Nah genug.
// `#totallyRandomNumber` ist eine statische private Eigenschaft.
static #totallyRandomNumber = 4;
// `#computeRandomNumber` ist eine statische private Methode.
static #computeRandomNumber() {
return FakeMath.#totallyRandomNumber;
}
// `random` ist eine statische öffentliche Methode (ES2015-Syntax)
// die `#computeRandomNumber` verwendet.
static random() {
console.log('Ich habe gehört, du magst Zufallszahlen…');
return FakeMath.#computeRandomNumber();
}
}
FakeMath.PI;
// → 3.142857142857143
FakeMath.random();
// protokolliert 'Ich habe gehört, du magst Zufallszahlen…'
// → 4
FakeMath.#totallyRandomNumber;
// → SyntaxError
FakeMath.#computeRandomNumber();
// → SyntaxError
Einfacheres Unterklassen-Erstellen
Die Vorteile der Klassenfeld-Syntax werden noch klarer, wenn es um Unterklassen geht, die zusätzliche Felder einführen. Stellen Sie sich die folgende Basisklasse Animal
vor:
class Animal {
constructor(name) {
this.name = name;
}
}
Um eine Cat
-Unterklasse zu erstellen, die eine zusätzliche Instanzeigenschaft einführt, musste man bisher super()
aufrufen, um den Konstruktor der Basisklasse Animal
auszuführen, bevor man die Eigenschaft erstellt:
class Cat extends Animal {
constructor(name) {
super(name);
this.likesBaths = false;
}
meow() {
console.log('Miau!');
}
}
Das ist eine Menge Boilerplate-Code, nur um anzugeben, dass Katzen keine Bäder mögen. Glücklicherweise entfernt die Klassenfeld-Syntax die Notwendigkeit für den gesamten Konstruktor, einschließlich des umständlichen super()
-Aufrufs:
class Cat extends Animal {
likesBaths = false;
meow() {
console.log('Miau!');
}
}