Statische Initialisierungsblöcke

Statische Initialisierungsblöcke werden innerhalb einer Klasse deklariert. Sie enthalten Anweisungen, die während der Klasseninitialisierung ausgewertet werden. Dies ermöglicht flexiblere Initialisierungslogik als statische Eigenschaften, wie z.B. die Verwendung von try...catch oder das Setzen mehrerer Felder aus einem einzelnen Wert. Die Initialisierung erfolgt im Kontext der aktuellen Klassendeklaration mit Zugriff auf privaten Zustand, was es der Klasse ermöglicht, Informationen ihrer privaten Eigenschaften mit anderen Klassen oder Funktionen im gleichen Geltungsbereich zu teilen (analog zu "Friend"-Klassen in C++).

Probieren Sie es aus

Syntax

js
class ClassWithSIB {
  static {
    // …
  }
}

Beschreibung

Ohne statische Initialisierungsblöcke könnte komplexe statische Initialisierung erreicht werden, indem eine statische Methode nach der Klassendeklaration aufgerufen wird:

js
class MyClass {
  static init() {
    // Access to private static fields is allowed here
  }
}

MyClass.init();

Dieses Vorgehen offenbart jedoch ein Implementierungsdetail (die init()-Methode) dem Nutzer der Klasse. Andererseits hat jegliche Initialisierungslogik, die außerhalb der Klasse deklariert wird, keinen Zugriff auf private statische Felder. Statische Initialisierungsblöcke ermöglichen es, beliebige Initialisierungslogik innerhalb der Klasse zu deklarieren und während der Klassenauswertung auszuführen.

Eine Klasse kann beliebig viele static {}-Initialisierungsblöcke in ihrem Klassenrumpf haben. Diese werden ausgewertet, zusammen mit beliebigen dazwischenliegenden statischen Felderinitialisierungen, in der Reihenfolge, in der sie deklariert sind. Jede statische Initialisierung einer Superklasse wird zuerst durchgeführt, bevor die der Unterklassen erfolgt.

Der Geltungsbereich der innerhalb des statischen Blocks deklarierten Variablen ist lokal zum Block. Dazu gehören Deklarationen mit var, function, const und let. var-Deklarationen werden nicht aus dem statischen Block herausgehoben.

js
var y = "Outer y";

class A {
  static field = "Inner y";
  static {
    // var y only hoisted inside block
    console.log(y); // undefined <-- not 'Outer y'

    var y = this.field;
  }
}

// var y defined in static block is not hoisted
// outside the block
console.log(y); // 'Outer y'

Das this innerhalb eines statischen Blocks bezieht sich auf das Konstruktorobjekt der Klasse. super.property kann verwendet werden, um auf statische Eigenschaften der Superklasse zuzugreifen. Beachten Sie jedoch, dass es ein Syntaxfehler ist, super() in einem Klasse-statischen Initialisierungsblock zu aufzurufen, oder das arguments-Objekt zu verwenden.

Die Anweisungen werden synchron ausgewertet. Sie können await oder yield in diesem Block nicht verwenden. (Betrachten Sie die Initialisierungsanweisungen als implizit in eine Funktion eingeschlossen.)

Der Geltungsbereich des statischen Blocks ist innerhalb des lexikalischen Bereichs des Klassenrumpfs verschachtelt und kann private Namen aufrufen, die innerhalb der Klasse deklariert sind, ohne einen Syntaxfehler zu verursachen.

Statische Felder-Initialisierungen und statische Initialisierungsblöcke werden nacheinander ausgewertet. Der Initialisierungsblock kann sich auf Feldwerte über ihm beziehen, aber nicht unterhalb. Alle statischen Methoden werden vorher hinzugefügt und sind erreichbar, obwohl deren Aufruf möglicherweise nicht wie erwartet funktioniert, wenn sie auf Felder unter dem aktuellen Block verweisen.

Hinweis: Dies ist wichtiger bei privaten statischen Feldern, da der Zugriff auf ein nicht initialisiertes privates Feld einen TypeError auslöst, selbst wenn das private Feld unterhalb deklariert ist. (Wenn das private Feld nicht deklariert ist, wäre es ein früher SyntaxError.)

Ein statischer Initialisierungsblock darf keine Dekorateure haben (die Klasse selbst möglicherweise).

Beispiele

Mehrere Blöcke

Der Code unten zeigt eine Klasse mit statischen Initialisierungsblöcken und dazwischenliegenden statischen Felderinitialisierungen. Die Ausgabe zeigt, dass die Blöcke und Felder in der Ausführungsreihenfolge ausgewertet werden.

js
class MyClass {
  static field1 = console.log("static field1");
  static {
    console.log("static block1");
  }
  static field2 = console.log("static field2");
  static {
    console.log("static block2");
  }
}
// 'static field1'
// 'static block1'
// 'static field2'
// 'static block2'

Beachten Sie, dass eine statische Initialisierung einer Superklasse zuerst durchgeführt wird, bevor die ihrer Unterklassen erfolgt.

Verwendung von this und super

Das this innerhalb eines statischen Blocks bezieht sich auf das Konstruktorobjekt der Klasse. Dieser Code zeigt, wie auf ein öffentliches statisches Feld zugegriffen wird.

js
class A {
  static field = "static field";
  static {
    console.log(this.field);
  }
}
// 'static field'

Die Syntax super.property kann innerhalb eines static-Blocks verwendet werden, um auf statische Eigenschaften einer Superklasse zuzugreifen.

js
class A {
  static field = "static field";
}

class B extends A {
  static {
    console.log(super.field);
  }
}
// 'static field'

Zugriff auf private Eigenschaften

Dieses Beispiel unten zeigt, wie der Zugriff auf ein privates Instanzfeld einer Klasse von einem Objekt außerhalb der Klasse gewährt werden kann (Beispiel vom v8.dev Blog):

js
let getDPrivateField;

class D {
  #privateField;
  constructor(v) {
    this.#privateField = v;
  }
  static {
    getDPrivateField = (d) => d.#privateField;
  }
}

console.log(getDPrivateField(new D("private"))); // 'private'

Spezifikationen

Specification
ECMAScript Language Specification
# prod-ClassStaticBlock

Browser-Kompatibilität

BCD tables only load in the browser

Siehe auch