Start · Sprachen · JavaScript · Referenz · Reflect.setPrototypeOf()

Reflect.setPrototypeOf()

Methode

Setzt den Prototyp (<code>[[Prototype]]</code>) eines Objekts und gibt <code>true</code> bei Erfolg bzw. <code>false</code> bei Misserfolg zurück, statt einen Fehler zu werfen.

seit JavaScript ES2015 Kategorie: method-property

Signatur

Reflect.setPrototypeOf(target, prototype)

Beschreibung

Reflect.setPrototypeOf() ändert den internen Prototyp eines Objekts, also den Wert, den auch Object.getPrototypeOf() liefert. Die Methode ruft direkt die interne Operation [[SetPrototypeOf]] auf und macht sie damit als normale Funktion zugänglich.

Der wichtigste Unterschied zu Object.setPrototypeOf() liegt beim Rückgabewert: Object.setPrototypeOf() gibt das Objekt zurück und wirft einen TypeError, wenn die Änderung nicht klappt. Reflect.setPrototypeOf() gibt dagegen einfach false zurück, zum Beispiel bei nicht erweiterbaren Objekten oder wenn eine Prototyp-Kette zum Kreis würde. So lässt sich der Erfolg ohne try...catch prüfen.

Am meisten nützt die Methode in Proxy-Handlern: Die Falle setPrototypeOf muss einen Boolean zurückgeben. Mit Reflect.setPrototypeOf(target, proto) leitet man die Operation genau passend an das Zielobjekt weiter.

Ist target kein Objekt, wirft die Methode einen TypeError. Object.setPrototypeOf() gibt primitive Werte dagegen einfach unverändert zurück.

Parameter

Name Typ Default Beschreibung
$target Pflicht Object Das Objekt, dessen Prototyp gesetzt werden soll. Muss ein Objekt sein, sonst wird ein TypeError geworfen.
$prototype Pflicht Object|null Der neue Prototyp. Erlaubt sind ein Objekt oder null, bei anderen Werten wird ein TypeError geworfen.

Rückgabewert

Typ
boolean
Beschreibung
true, wenn der Prototyp gesetzt wurde (auch wenn er schon derselbe war). false, wenn die Änderung abgelehnt wurde, etwa bei nicht erweiterbaren Objekten oder zirkulären Prototyp-Ketten.

Beispiele

Prototyp setzen und Erfolg prüfen

const tier = {
  sprich() {
    return `${this.name} macht ein Geräusch.`;
  }
};

const hund = { name: 'Bello' };

const ok = Reflect.setPrototypeOf(hund, tier);
console.log(ok);
console.log(hund.sprich());
console.log(Object.getPrototypeOf(hund) === tier);
true Bello macht ein Geräusch. true

false statt Fehler bei nicht erweiterbaren Objekten und Kreisen

const eingefroren = Object.freeze({});
console.log(Reflect.setPrototypeOf(eingefroren, {}));

// Zum Vergleich: Object.setPrototypeOf wirft einen Fehler
try {
  Object.setPrototypeOf(eingefroren, {});
} catch (err) {
  console.log(err instanceof TypeError);
}

// Zirkuläre Prototyp-Kette wird abgelehnt
const a = {};
const b = Object.create(a);
console.log(Reflect.setPrototypeOf(a, b));

// Prototyp null ist erlaubt
console.log(Reflect.setPrototypeOf({}, null));
false true false true

Weiterleitung in einer Proxy-Falle

const ziel = {};

const geschuetzt = new Proxy(ziel, {
  setPrototypeOf(target, proto) {
    if (proto === null) {
      console.log('Prototyp null ist nicht erlaubt');
      return false;
    }
    console.log('Prototyp wird geändert');
    return Reflect.setPrototypeOf(target, proto);
  }
});

console.log(Reflect.setPrototypeOf(geschuetzt, Array.prototype));
console.log(Reflect.setPrototypeOf(geschuetzt, null));
Prototyp wird geändert true Prototyp null ist nicht erlaubt false

// Wichtig · Fallstricke

  • Performance: Wenn man den Prototyp eines bestehenden Objekts nachträglich ändert, können JavaScript-Engines die internen Optimierungen für dieses Objekt nicht mehr nutzen. Das betrifft auch jeden späteren Zugriff darauf. Besser ist es, Objekte gleich mit Object.create(proto) oder über class ... extends anzulegen.
  • Ist target ein primitiver Wert, wirft die Methode einen TypeError. Ist prototype weder ein Objekt noch null, gibt es ebenfalls einen TypeError. Nur abgelehnte Änderungen führen zu false.
  • Bei unveränderlichen exotischen Objekten wie Object.prototype gibt die Methode false zurück, sobald man einen anderen Prototyp setzen will.
  • Den Rückgabewert immer prüfen: Anders als bei Object.setPrototypeOf() scheitert der Aufruf sonst unbemerkt.
  • Browser-Unterstützung: Baseline, in allen modernen Browsern und seit Node.js 6 verfügbar. Der Internet Explorer unterstützt die Methode nicht.