Start · Sprachen · JavaScript · Referenz · new.target

new.target

Keyword

Die Meta-Eigenschaft <code>new.target</code> zeigt an, ob eine Funktion oder ein Konstruktor mit <code>new</code> aufgerufen wurde, und verweist dann auf den aufgerufenen Konstruktor.

seit JavaScript ES2015 – Baseline: alle modernen Browser, Node.js Kategorie: syntax

Signatur

new.target

Beschreibung

new.target ist eine Meta-Eigenschaft. Sie ist also kein normales Objekt mit Eigenschaft, sondern eine besondere Syntaxform, die in jeder Funktion und in jedem Klassenkörper zur Verfügung steht. Wird eine Funktion mit new aufgerufen, verweist new.target auf den Konstruktor, den new direkt aufgerufen hat. Bei einem normalen Funktionsaufruf ist der Wert undefined.

Typische Einsatzfälle sind:

  • Aufruf ohne new erkennen: In klassischen Konstruktorfunktionen kann man damit eine Fehlermeldung werfen oder den Aufruf automatisch auf new umleiten.
  • Abstrakte Basisklassen: Prüft man new.target === Basisklasse, lässt sich verhindern, dass die Basisklasse direkt instanziiert wird. Nur Unterklassen sind dann erlaubt.
  • Fabrik- und Registrierungslogik: Im Konstruktor der Basisklasse verweist new.target auf die tatsächlich instanziierte Unterklasse. So kommt man etwa an new.target.name oder an statische Eigenschaften der Unterklasse.

In Klassen-Konstruktoren ist new.target nie undefined, weil Klassen ohnehin nur mit new aufgerufen werden können. Pfeilfunktionen haben kein eigenes new.target. Sie übernehmen den Wert aus der umgebenden Funktion, genau wie bei this. Außerhalb von Funktionen, also direkt im Skript oder Modul, führt new.target zu einem SyntaxError.

Rückgabewert

Typ
Function | undefined
Beschreibung
Die Konstruktorfunktion oder Klasse, auf die new direkt angewendet wurde. Bei Vererbung ist das die abgeleitete Klasse. Ohne new ist der Wert undefined. Bei Reflect.construct(target, args, newTarget) ist es der übergebene newTarget.

Beispiele

Aufruf ohne new erkennen und abfangen

function User(name) {
  if (!new.target) {
    // Ohne new aufgerufen: automatisch korrigieren
    return new User(name);
  }
  this.name = name;
}

const a = new User('Anna');
const b = User('Ben'); // kein new

console.log(a instanceof User, a.name);
console.log(b instanceof User, b.name);
true Anna true Ben

Abstrakte Basisklasse erzwingen

class Shape {
  constructor() {
    if (new.target === Shape) {
      throw new TypeError('Shape ist abstrakt und kann nicht direkt instanziiert werden.');
    }
  }
  area() {
    throw new Error('area() muss überschrieben werden');
  }
}

class Circle extends Shape {
  constructor(r) {
    super();
    this.r = r;
  }
  area() {
    return Math.PI * this.r ** 2;
  }
}

console.log(new Circle(2).area().toFixed(2));

try {
  new Shape();
} catch (err) {
  console.log(err.message);
}
12.57 Shape ist abstrakt und kann nicht direkt instanziiert werden.

Unterklasse im Basiskonstruktor erkennen

class Model {
  static tableName = 'models';
  constructor() {
    // new.target zeigt auf die tatsächlich instanziierte Klasse
    this.type = new.target.name;
    this.table = new.target.tableName;
  }
}

class Product extends Model {
  static tableName = 'products';
}

console.log(new Product());
console.log(new Model());
Product { type: 'Product', table: 'products' } Model { type: 'Model', table: 'models' }

Pfeilfunktionen und Reflect.construct

function Outer() {
  const inner = () => new.target; // übernimmt new.target von Outer
  return { fromArrow: inner() === Outer };
}
console.log(new Outer().fromArrow);

function Base() {
  this.target = new.target.name;
}
class Other {}

const obj = Reflect.construct(Base, [], Other);
console.log(obj.target, obj instanceof Other);
true Other true

// Wichtig · Fallstricke

  • Nur innerhalb von Funktionen erlaubt: Auf oberster Ebene eines Skripts oder Moduls führt new.target zu einem SyntaxError. Innerhalb von eval() ist es nur zulässig, wenn der Aufruf in einer Funktion steht.
  • Pfeilfunktionen haben kein eigenes new.target. Sie lassen sich ohnehin nicht mit new aufrufen. Deshalb sehen sie den Wert der umgebenden Funktion. In Klassenfeld-Initialisierern und statischen Blöcken ist new.target immer undefined.
  • Methoden-Aufrufe: Normale Methoden wie obj.method() und Funktionen, die über call/apply aufgerufen werden, haben new.target === undefined.
  • Die Prüfung this instanceof Foo ist kein gleichwertiger Ersatz. Sie lässt sich mit Foo.call(Object.create(Foo.prototype)) austricksen, new.target dagegen nicht.
  • new.target verweist bei Vererbung immer auf die äußerste Klasse. Wer die Basisklasse vergleichen will, sollte deshalb ausdrücklich new.target === Base prüfen.
  • Kompatibilität: Wird seit ES2015 von allen modernen Browsern und Node.js unterstützt, nicht vom Internet Explorer. Transpiler wie Babel können es nur teilweise nachbilden.