Signatur
Beschreibung
Reflect.construct() ist die funktionale Form von new target(...argumentsList). Die Argumente werden als array-ähnliches Objekt übergeben. So kann man Konstruktoren dynamisch aufrufen, ohne die Anzahl der Argumente vorher zu kennen. Das ist besonders in Fabrik-Funktionen, Dependency-Injection-Containern und Proxy-Traps nützlich.
Ein Vorteil gegenüber new ist der optionale dritte Parameter newTarget. Er legt fest, welchen Wert new.target im Konstruktor hat und von welchem prototype das neue Objekt erbt. Der Code von target läuft also, das Ergebnis ist aber eine Instanz von newTarget. Mit Object.create() und Function.prototype.apply() lässt sich das nicht korrekt nachbauen, weil dort new.target undefined bleibt und eingebaute Klassen wie Date oder Map ihre internen Slots nicht bekommen.
Typischer Einsatz ist der construct-Trap eines Proxy. Dort gibt Reflect.construct(target, args, newTarget) den Aufruf unverändert an das Originalziel weiter, und Vererbung sowie new.target bleiben dabei erhalten.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $target Pflicht | Function | Der Konstruktor, der aufgerufen wird. Er muss konstruierbar sein, sonst wird ein TypeError geworfen. Pfeilfunktionen und normale Methoden sind zum Beispiel nicht konstruierbar. |
|
| $argumentsList Pflicht | Array|ArrayLike | Array-ähnliches Objekt mit den Argumenten für target. Es ist Pflicht; ohne Argumente übergibt man []. |
|
| $newTarget | Function | target | Der Konstruktor, dessen prototype das neue Objekt bekommt. Im Konstruktor ist er als new.target sichtbar. Auch er muss konstruierbar sein. |
Beispiele
Grundlegender Aufruf statt new
const d1 = new Date(2024, 0, 15);
const d2 = Reflect.construct(Date, [2024, 0, 15]);
console.log(d1.getTime() === d2.getTime());
console.log(d2 instanceof Date);
Dynamische Fabrik-Funktion
class User {
constructor(name, role = 'gast') {
this.name = name;
this.role = role;
}
}
class Product {
constructor(title, price) {
this.title = title;
this.price = price;
}
}
const registry = { User, Product };
const create = (typeName, ...args) => {
const Ctor = registry[typeName];
if (!Ctor) throw new Error(`Unbekannter Typ: ${typeName}`);
return Reflect.construct(Ctor, args);
};
console.log(create('User', 'Anna', 'admin'));
console.log(create('Product', 'Tastatur', 49.9));
newTarget: Konstruktor-Code von A, Prototyp von B
class Animal {
constructor(name) {
this.name = name;
console.log('new.target:', new.target.name);
}
}
class Dog {
bark() { return `${this.name} bellt!`; }
}
const rex = Reflect.construct(Animal, ['Rex'], Dog);
console.log(rex instanceof Dog, rex instanceof Animal);
console.log(rex.bark());
Proxy-construct-Trap mit Protokollierung
class Connection {
constructor(host, port) {
this.url = `${host}:${port}`;
}
}
const LoggedConnection = new Proxy(Connection, {
construct(target, args, newTarget) {
console.log(`Erzeuge ${target.name} mit`, args);
// new.target und Prototyp bleiben erhalten
return Reflect.construct(target, args, newTarget);
}
});
const conn = new LoggedConnection('localhost', 5432);
console.log(conn.url, conn instanceof Connection);
// Wichtig · Fallstricke
- TypeError bei nicht konstruierbaren Zielen: Pfeilfunktionen, Methoden aus Kurzschreibweise,
async-Funktionen, Generatoren und Funktionen wieMath.maxlösen einenTypeErroraus. Dasselbe gilt, wennnewTargetnicht konstruierbar ist. argumentsListist Pflicht:Reflect.construct(Foo)ohne zweites Argument wirft einenTypeError. Ohne Argumente übergibt man[].- Anderes Verhalten als
Object.create()+apply(): Bei diesem älteren Muster istnew.targetundefined. Klassen lassen sich damit gar nicht aufrufen, weil ein Klassenkonstruktor ohneneweinenTypeErrorwirft. Eingebaute Objekte wieDate,MapoderErrorbekommen außerdem ihre internen Slots nicht.Reflect.construct()hat diese Probleme nicht. - Proxy-Traps: Im
construct-Trap immernewTargetweiterreichen. Sonst funktioniertclass Sub extends ProxiedClassnicht richtig, weil die Instanz den falschen Prototyp bekommt. - Kompatibilität: Wird von allen modernen Browsern und von Node.js ab Version 6 unterstützt. Der Internet Explorer kennt die Methode nicht.