Signatur
Beschreibung
Jede „normale“ Funktion (Funktionsdeklaration, Funktionsausdruck, class) hat eine eigene Daten-Eigenschaft prototype. Ruft man die Funktion mit new auf, erzeugt die Engine ein neues Objekt, dessen internes [[Prototype]] auf funktion.prototype zeigt. Methoden und gemeinsame Eigenschaften, die dort liegen, stehen so allen Instanzen über die Prototypenkette zur Verfügung, ohne pro Instanz kopiert zu werden.
Standardmäßig ist prototype ein einfaches Objekt mit genau einer Eigenschaft: constructor, die zurück auf die Funktion verweist. Die Eigenschaft ist beschreibbar, nicht aufzählbar und nicht konfigurierbar. Bei Klassen ist prototype dagegen nicht beschreibbar.
Wichtig ist der Unterschied zu Object.getPrototypeOf(obj) bzw. obj.__proto__: funktion.prototype ist nicht der Prototyp der Funktion selbst (der ist Function.prototype), sondern die Vorlage für ihre Instanzen. Diese Eigenschaft wird auch von instanceof ausgewertet.
Pfeilfunktionen, Methoden-Kurzschreibweisen, async-Funktionen und die meisten eingebauten Funktionen (z. B. Math.max) haben keine prototype-Eigenschaft und können nicht mit new aufgerufen werden. Generatorfunktionen haben eine prototype-Eigenschaft (Prototyp der erzeugten Generator-Objekte), lassen sich aber trotzdem nicht als Konstruktor verwenden.
Rückgabewert
new erzeugt werden; standardmäßig { constructor: funktion }. Bei Funktionen ohne Konstruktor-Fähigkeit (Pfeilfunktionen, Methoden) undefined.Beispiele
Gemeinsame Methoden für Konstruktor-Instanzen
function Benutzer(name) {
this.name = name;
}
// Methode einmal auf dem Prototyp ablegen statt pro Instanz
Benutzer.prototype.begruessen = function () {
return `Hallo, ${this.name}!`;
};
const anna = new Benutzer('Anna');
const ben = new Benutzer('Ben');
console.log(anna.begruessen());
console.log(anna.begruessen === ben.begruessen);
console.log(Object.getPrototypeOf(anna) === Benutzer.prototype);
console.log(anna instanceof Benutzer);
Standardinhalt und fehlende prototype-Eigenschaft
function Punkt() {}
const pfeil = () => {};
const obj = { methode() {} };
console.log(Object.getOwnPropertyNames(Punkt.prototype));
console.log(Punkt.prototype.constructor === Punkt);
console.log(pfeil.prototype);
console.log(obj.methode.prototype);
console.log(Object.getOwnPropertyDescriptor(Punkt, 'prototype'));
Vererbung ohne class-Syntax (und constructor reparieren)
function Tier(name) {
this.name = name;
}
Tier.prototype.sprechen = function () {
return `${this.name} macht ein Geräusch.`;
};
function Hund(name) {
Tier.call(this, name);
}
// Prototypenkette aufbauen
Hund.prototype = Object.create(Tier.prototype);
Hund.prototype.constructor = Hund; // sonst zeigt constructor auf Tier
Hund.prototype.sprechen = function () {
return `${this.name} bellt.`;
};
const rex = new Hund('Rex');
console.log(rex.sprechen());
console.log(rex instanceof Tier, rex.constructor.name);
Klassen: prototype ist schreibgeschützt
class Konto {
einzahlen(betrag) { return betrag; }
}
console.log(typeof Konto.prototype.einzahlen);
Konto.prototype = {}; // wird im Sloppy-Mode still ignoriert
console.log(Object.getOwnPropertyNames(Konto.prototype));
console.log(Object.getOwnPropertyDescriptor(Konto, 'prototype').writable);
// Wichtig · Fallstricke
- Verwechslungsgefahr:
fn.prototypeist nicht der Prototyp vonfn. Den ermittelt man mitObject.getPrototypeOf(fn)(in der RegelFunction.prototype). - Ersetzen statt Erweitern: Wer
Fn.prototype = { ... }zuweist, verliert dieconstructor-Eigenschaft und sollte sie wiederherstellen. Bereits erzeugte Instanzen behalten den alten Prototyp, undinstanceofliefert für sie danachfalse. - Ist
Fn.prototypebeimnew-Aufruf kein Objekt (z. B.nulloder eine Zahl), erhält die Instanz stattdessenObject.prototypeals Prototyp. - Bei
classistprototypenicht beschreibbar; eine Zuweisung wirft im Strict-Mode (also auch in Modulen und Klassenrümpfen) einenTypeError. - Eingebaute Prototypen (
Array.prototype,Object.prototype) nicht erweitern: Das kann mit künftigen Standards kollidieren und öffnet Wege für Prototype-Pollution-Angriffe. Beim Zusammenführen nicht vertrauenswürdiger Objekte Schlüssel wie__proto__,constructorundprototypefiltern. - Methoden auf dem Prototyp sparen Speicher gegenüber Methoden, die im Konstruktor per
this.methode = ...für jede Instanz neu angelegt werden.