constructor
Baseline
Weitgehend verfügbar
Diese Funktion ist gut etabliert und funktioniert auf vielen Geräten und in vielen Browserversionen. Sie ist seit März 2016 browserübergreifend verfügbar.
Die constructor-Methode ist eine spezielle Methode einer Klasse, mit der eine Objektinstanz dieser Klasse erstellt und initialisiert wird.
Hinweis:
Diese Seite erläutert die constructor-Syntax. Informationen zur constructor-Eigenschaft, die auf allen Objekten vorhanden ist, finden Sie unter Object.prototype.constructor.
Probieren Sie es aus
class Polygon {
constructor() {
this.name = "Polygon";
}
}
const poly = new Polygon();
console.log(poly.name);
// Expected output: "Polygon"
Syntax
constructor() { /* … */ }
constructor(argument0) { /* … */ }
constructor(argument0, argument1) { /* … */ }
constructor(argument0, argument1, /* …, */ argumentN) { /* … */ }
Es gelten einige zusätzliche Syntaxbeschränkungen:
- Eine nicht statische Klassenmethode mit dem nicht berechneten Namen
constructordarf kein Getter, Setter, keine asynchrone Funktion und kein Generator sein. - Eine Klasse darf nicht mehr als eine
constructor-Methode haben.
Beschreibung
Mit einem Konstruktor können Sie eine benutzerdefinierte Initialisierung vornehmen, die erforderlich ist, bevor andere Methoden auf einem instanziierten Objekt aufgerufen werden können.
class Person {
constructor(name) {
this.name = name;
}
introduce() {
console.log(`Hello, my name is ${this.name}`);
}
}
const otto = new Person("Otto");
otto.introduce(); // Hello, my name is Otto
Wenn Sie keinen eigenen Konstruktor bereitstellen, wird ein Standardkonstruktor verwendet. Bei einer Basisklasse ist der Standardkonstruktor leer:
constructor() {}
Bei einer abgeleiteten Klasse ruft der Standardkonstruktor den Konstruktor der Elternklasse auf und gibt alle übergebenen Argumente weiter:
constructor(...args) {
super(...args);
}
Hinweis: Der Unterschied zwischen einem expliziten Konstruktor wie dem oben gezeigten und dem Standardkonstruktor besteht darin, dass Letzterer bei der Verteilung der Argumente nicht tatsächlich den Array-Iterator aufruft.
Dadurch funktioniert beispielsweise folgender Code:
class ValidationError extends Error {
printCustomerMessage() {
return `Validation failed :-( (details: ${this.message})`;
}
}
try {
throw new ValidationError("Not a valid phone number");
} catch (error) {
if (error instanceof ValidationError) {
console.log(error.name); // This is Error instead of ValidationError!
console.log(error.printCustomerMessage());
} else {
console.log("Unknown error", error);
throw error;
}
}
Die Klasse ValidationError benötigt keinen expliziten Konstruktor, da sie keine benutzerdefinierte Initialisierung vornehmen muss.
Der Standardkonstruktor übernimmt die Initialisierung der Elternklasse Error mit dem übergebenen Argument.
Wenn Sie jedoch einen eigenen Konstruktor bereitstellen und Ihre Klasse von einer Elternklasse abgeleitet ist, müssen Sie den Konstruktor der Elternklasse ausdrücklich mit super() aufrufen.
Zum Beispiel:
class ValidationError extends Error {
constructor(message) {
super(message); // call parent class constructor
this.name = "ValidationError";
this.code = "42";
}
printCustomerMessage() {
return `Validation failed :-( (details: ${this.message}, code: ${this.code})`;
}
}
try {
throw new ValidationError("Not a valid phone number");
} catch (error) {
if (error instanceof ValidationError) {
console.log(error.name); // Now this is ValidationError!
console.log(error.printCustomerMessage());
} else {
console.log("Unknown error", error);
throw error;
}
}
Bei der Verwendung von new mit einer Klasse werden die folgenden Schritte durchlaufen:
- Bei einer abgeleiteten Klasse wird der Teil des
constructor-Rumpfs vor dem Aufruf vonsuper()ausgeführt. Dieser Teil darf nicht aufthiszugreifen, da es noch nicht initialisiert ist. - Bei einer abgeleiteten Klasse wird
super()aufgerufen, wodurch die Elternklasse nach demselben Verfahren initialisiert wird. - Die Felder der aktuellen Klasse werden initialisiert.
- Der Teil des
constructor-Rumpfs nach dem Aufruf vonsuper()wird ausgeführt. Bei einer Basisklasse wird der gesamte Rumpf ausgeführt.
Innerhalb des constructor-Rumpfs können Sie über this auf das zu erstellende Objekt und über new.target auf die Klasse zugreifen, mit der new aufgerufen wurde. Beachten Sie, dass Methoden (einschließlich Getter und Setter) und die Prototypkette auf this bereits initialisiert sind, bevor constructor ausgeführt wird. Daher können Sie vom Konstruktor der Oberklasse aus sogar auf Methoden der Unterklasse zugreifen. Wenn diese Methoden jedoch this verwenden, ist this zu diesem Zeitpunkt noch nicht vollständig initialisiert. Das bedeutet, dass das Lesen öffentlicher Felder der abgeleiteten Klasse undefined ergibt, während das Lesen privater Felder einen TypeError auslöst.
new (class C extends class B {
constructor() {
console.log(this.foo());
}
} {
#a = 1;
foo() {
return this.#a; // TypeError: Cannot read private member #a from an object whose class did not declare it
// It's not really because the class didn't declare it,
// but because the private field isn't initialized yet
// when the superclass constructor is running
}
})();
Die constructor-Methode kann einen Wert zurückgeben. Während der Konstruktor einer Basisklasse einen beliebigen Wert zurückgeben kann, muss der Konstruktor einer abgeleiteten Klasse ein Objekt oder undefined zurückgeben. Andernfalls wird ein TypeError ausgelöst.
class ParentClass {
constructor() {
return 1;
}
}
console.log(new ParentClass()); // ParentClass {}
// The return value is ignored because it's not an object
// This is consistent with function constructors
class ChildClass extends ParentClass {
constructor() {
return 1;
}
}
console.log(new ChildClass()); // TypeError: Derived constructors may only return object or undefined
Wenn der Konstruktor der Elternklasse ein Objekt zurückgibt, wird dieses Objekt als this-Wert verwendet, auf dem die Klassenfelder der abgeleiteten Klasse definiert werden. Dieser Mechanismus wird als „return overriding“ bezeichnet. Er ermöglicht es, Felder einer abgeleiteten Klasse (auch private Felder) auf Objekten zu definieren, die nicht zur Klassenhierarchie gehören.
Für constructor gilt die normale Methodensyntax. Daher können unter anderem Standardwerte für Parameter und Rest-Parameter verwendet werden.
class Person {
constructor(name = "Anonymous") {
this.name = name;
}
introduce() {
console.log(`Hello, my name is ${this.name}`);
}
}
const person = new Person();
person.introduce(); // Hello, my name is Anonymous
Der Name des Konstruktors muss wörtlich angegeben werden. Berechnete Eigenschaften können keine Konstruktoren sein.
Nicht statische asynchrone Methoden, Generatormethoden und Accessors dürfen nicht den nicht berechneten Namen constructor tragen. Auch statische und Instanz-Klassenfelder dürfen nicht den nicht berechneten Namen constructor tragen. Private Namen dürfen nicht #constructor lauten. Jedes nicht statische Mitglied mit dem nicht berechneten Namen constructor muss eine gewöhnliche Methode sein.
Beispiele
>Den Konstruktor verwenden
Dieser Codeausschnitt stammt aus dem Klassenbeispiel (Live-Demo).
class Square extends Polygon {
constructor(length) {
// Here, it calls the parent class' constructor with lengths
// provided for the Polygon's width and height
super(length, length);
// NOTE: In derived classes, `super()` must be called before you
// can use `this`. Leaving this out will cause a ReferenceError.
this.name = "Square";
}
get area() {
return this.height * this.width;
}
set area(value) {
this.height = value ** 0.5;
this.width = value ** 0.5;
}
}
super in einem Konstruktor aufrufen, der an einen anderen Prototyp gebunden ist
super() ruft den Konstruktor auf, der der Prototyp der aktuellen Klasse ist. Wenn Sie den Prototyp der aktuellen Klasse selbst ändern, ruft super() den Konstruktor auf, der der neue Prototyp ist. Eine Änderung des Prototyps der prototype-Eigenschaft der aktuellen Klasse hat keinen Einfluss darauf, welchen Konstruktor super() aufruft.
class Polygon {
constructor() {
this.name = "Polygon";
}
}
class Rectangle {
constructor() {
this.name = "Rectangle";
}
}
class Square extends Polygon {
constructor() {
super();
}
}
// Make Square extend Rectangle (which is a base class) instead of Polygon
Object.setPrototypeOf(Square, Rectangle);
const newInstance = new Square();
// newInstance is still an instance of Polygon, because we didn't
// change the prototype of Square.prototype, so the prototype chain
// of newInstance is still
// newInstance --> Square.prototype --> Polygon.prototype
console.log(newInstance instanceof Polygon); // true
console.log(newInstance instanceof Rectangle); // false
// However, because super() calls Rectangle as constructor, the name property
// of newInstance is initialized with the logic in Rectangle
console.log(newInstance.name); // Rectangle
Spezifikationen
| Spezifikation |
|---|
| ECMAScript® 2027 Language Specification> # sec-static-semantics-constructormethod> |