Zum Hauptinhalt springen

Öffentliche und private Klassenfelder

· 4 Minuten Lesezeit
Mathias Bynens ([@mathias](https://twitter.com/mathias))

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!');
}
}

Feature-Unterstützung

Unterstützung für öffentliche Klassenfelder

Unterstützung für private Klassenfelder

Unterstützung für private Methoden und Zugriffe