Object.setPrototypeOf()
Baseline
Weitgehend verfügbar
Diese Funktion ist gut etabliert und funktioniert auf vielen Geräten und in vielen Browserversionen. Sie ist seit September 2015 browserübergreifend verfügbar.
Die statische Methode Object.setPrototypeOf() setzt den Prototyp (d.h. die interne Eigenschaft [[Prototype]]) eines angegebenen Objekts auf ein anderes Objekt oder auf null.
Warnung:
Das Ändern von [[Prototype]] eines Objekts ist aufgrund der Art und Weise, wie moderne JavaScript-Engines Eigenschaftszugriffe optimieren, derzeit in jedem Browser und jeder JavaScript-Engine ein sehr langsamer Vorgang. Zudem sind die Auswirkungen einer Änderung der Vererbung subtil und weitreichend. Sie beschränken sich nicht auf die Ausführungszeit der Anweisung Object.setPrototypeOf(...), sondern können sich auf jeden Code erstrecken, der Zugriff auf ein Objekt hat, dessen [[Prototype]] geändert wurde. Weitere Informationen finden Sie unter Grundlagen von JavaScript-Engines: Prototypen optimieren.
Da diese Funktion Teil der Sprache ist, liegt es dennoch an den Entwicklern von JavaScript-Engines, sie möglichst performant zu implementieren. Solange dieses Problem nicht behoben ist, sollten Sie das Setzen von [[Prototype]] eines Objekts vermeiden, wenn Ihnen die Performance wichtig ist. Erstellen Sie stattdessen mit Object.create() ein neues Objekt mit dem gewünschten [[Prototype]].
Probieren Sie es aus
const obj = {};
const parent = { foo: "bar" };
console.log(obj.foo);
// Expected output: undefined
Object.setPrototypeOf(obj, parent);
console.log(obj.foo);
// Expected output: "bar"
Syntax
Object.setPrototypeOf(obj, prototype)
Parameter
Rückgabewert
Das angegebene Objekt.
Ausnahmen
TypeError-
Wird in einem der folgenden Fälle ausgelöst:
- Der Parameter
objistundefinedodernull. - Der Parameter
objist nicht erweiterbar oder ein exotisches Objekt mit unveränderlichem Prototyp, etwaObject.prototypeoderwindow. Der Fehler wird jedoch nicht ausgelöst, wenn der neue Prototyp denselben Wert wie der ursprüngliche Prototyp vonobjhat. - Der Parameter
prototypeist weder ein Objekt nochnull.
- Der Parameter
Beschreibung
Object.setPrototypeOf() gilt allgemein als der richtige Weg, den Prototyp eines Objekts zu setzen. Sie sollten diese Methode immer dem veralteten Accessor Object.prototype.__proto__ vorziehen.
Wenn der Parameter obj kein Objekt ist (z. B. eine Zahl oder eine Zeichenfolge), führt diese Methode nichts aus: Sie wandelt obj weder in ein Objekt um noch versucht sie, dessen Prototyp zu setzen. Stattdessen gibt sie obj direkt als primitiven Wert zurück. Wenn prototype denselben Wert wie der Prototyp von obj hat, wird obj ebenfalls direkt zurückgegeben, ohne einen TypeError auszulösen – selbst wenn obj einen unveränderlichen Prototyp hat.
Aus Sicherheitsgründen haben bestimmte integrierte Objekte einen unveränderlichen Prototyp. Dies verhindert Prototype-Pollution-Angriffe, insbesondere solche im Zusammenhang mit Proxys. Die Sprachspezifikation selbst legt nur Object.prototype als exotisches Objekt mit unveränderlichem Prototyp fest; sein Prototyp ist immer null. In Browsern sind window und location zwei weitere häufige Beispiele.
Object.isExtensible(Object.prototype); // true; you can add more properties
Object.setPrototypeOf(Object.prototype, {}); // TypeError: Immutable prototype object '#<Object>' cannot have their prototype set
Object.setPrototypeOf(Object.prototype, null); // No error; the prototype of `Object.prototype` is already `null`
Beispiele
>Pseudoklassische Vererbung mit Object.setPrototypeOf()
Vererbung in JS mithilfe von Klassen.
class Human {}
class SuperHero extends Human {}
const superMan = new SuperHero();
Wenn wir jedoch Unterklassen ohne class implementieren möchten, können wir wie folgt vorgehen:
function Human(name, level) {
this.name = name;
this.level = level;
}
function SuperHero(name, level) {
Human.call(this, name, level);
}
Object.setPrototypeOf(SuperHero.prototype, Human.prototype);
// Set the `[[Prototype]]` of `SuperHero.prototype`
// to `Human.prototype`
// To set the prototypal inheritance chain
Human.prototype.speak = function () {
return `${this.name} says hello.`;
};
SuperHero.prototype.fly = function () {
return `${this.name} is flying.`;
};
const superMan = new SuperHero("Clark Kent", 1);
console.log(superMan.fly());
console.log(superMan.speak());
Die Ähnlichkeit zwischen klassischer Vererbung (mit Klassen) und pseudoklassischer Vererbung (mit der Eigenschaft prototype von Konstruktoren), wie oben gezeigt, wird unter Vererbungsketten erläutert.
Da die Eigenschaft prototype von Funktionskonstruktoren schreibbar ist, können Sie ihr ein neues, mit Object.create() erstelltes Objekt zuweisen, um dieselbe Vererbungskette zu erreichen. Bei der Verwendung von create() sind einige Besonderheiten zu beachten. Denken Sie beispielsweise daran, die Eigenschaft constructor wieder hinzuzufügen.
Im folgenden Beispiel, das ebenfalls Klassen verwendet, erbt SuperHero von Human. Statt extends wird dafür setPrototypeOf() verwendet.
Warnung:
Aus Gründen der Performance und Lesbarkeit ist es nicht ratsam, setPrototypeOf() anstelle von extends zu verwenden.
class Human {}
class SuperHero {}
// Set the instance properties
Object.setPrototypeOf(SuperHero.prototype, Human.prototype);
// Hook up the static properties
Object.setPrototypeOf(SuperHero, Human);
const superMan = new SuperHero();
Die Definition von Unterklassen ohne extends wird unter ES-6-Unterklassen erläutert.
Spezifikationen
| Spezifikation |
|---|
| ECMAScript® 2027 Language Specification> # sec-object.setprototypeof> |