Signatur
Beschreibung
Symbol.hasInstance ist eine statische Dateneigenschaft von Symbol. Sie enthält das bekannte Symbol (engl. well-known symbol) @@hasInstance. Beim Ausdruck x instanceof C sucht die Engine zuerst nach der Methode C[Symbol.hasInstance]. Gibt es sie, ruft die Engine sie mit x als Argument auf und wandelt das Ergebnis in einen booleschen Wert um. Gibt es sie nicht, prüft sie wie üblich die Prototypkette.
Damit lässt sich instanceof anpassen, zum Beispiel für Duck-Typing (ein Objekt gilt als Instanz, wenn es bestimmte Methoden hat), für Typprüfungen über mehrere Realms hinweg (iframes, vm-Kontexte in Node.js) oder für „Typ-Objekte“, die gar keine Konstruktoren sind.
Function.prototype[Symbol.hasInstance] ist die Standardimplementierung, die alle Funktionen erben. Sie ist nicht beschreibbar (writable: false). Eine bloße Zuweisung wie MyClass[Symbol.hasInstance] = fn hat deshalb keine Wirkung. Im Strict Mode wirft sie sogar einen TypeError. Eigene Implementierungen legt man deshalb mit static [Symbol.hasInstance](obj) in einer Klasse oder mit Object.defineProperty an.
Die Eigenschaft selbst ist nicht beschreibbar, nicht aufzählbar und nicht konfigurierbar.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $instance Pflicht | any | Beim Aufruf der Methode [Symbol.hasInstance](instance): der linke Operand von instanceof, also der Wert, der geprüft wird. |
Rückgabewert
Symbol.hasInstance. Eine Methode, die unter diesem Schlüssel hinterlegt ist, sollte einen booleschen Wert zurückgeben. Andere Rückgabewerte wandelt instanceof mit ToBoolean um.Beispiele
Duck-Typing mit instanceof
class Iterierbar {
static [Symbol.hasInstance](obj) {
return obj != null && typeof obj[Symbol.iterator] === 'function';
}
}
console.log([1, 2, 3] instanceof Iterierbar);
console.log('abc' instanceof Iterierbar);
console.log(new Map() instanceof Iterierbar);
console.log({} instanceof Iterierbar);
Typ-Objekt ohne Konstruktor
const Gerade = {
[Symbol.hasInstance]: (n) => Number.isInteger(n) && n % 2 === 0
};
const werte = [1, 2, 7, 10, 3.5];
console.log(werte.filter((w) => w instanceof Gerade));
Zuweisung vs. Object.defineProperty
'use strict';
function Punkt(x, y) { this.x = x; this.y = y; }
try {
// schlägt fehl: geerbte Eigenschaft ist nicht beschreibbar
Punkt[Symbol.hasInstance] = () => true;
} catch (e) {
console.log(e.constructor.name);
}
Object.defineProperty(Punkt, Symbol.hasInstance, {
value: (obj) => typeof obj?.x === 'number' && typeof obj?.y === 'number'
});
console.log({ x: 1, y: 2 } instanceof Punkt);
Standardverhalten direkt aufrufen
class Tier {}
class Hund extends Tier {}
const bello = new Hund();
// entspricht bello instanceof Tier
console.log(Tier[Symbol.hasInstance](bello));
console.log(Function.prototype[Symbol.hasInstance].call(Tier, {}));
// Wichtig · Fallstricke
- Nicht beschreibbar:
Function.prototype[Symbol.hasInstance]hatwritable: false. Eine einfache Zuweisung an einen Konstruktor überschreibt die Methode deshalb nicht. Im Sloppy Mode passiert dabei still nichts, im Strict Mode wird einTypeErrorgeworfen. Verwende stattdessenstatic [Symbol.hasInstance]oderObject.defineProperty. - Ist der rechte Operand kein Objekt, wirft
instanceofeinenTypeError. Dasselbe passiert, wenn er weder eine[Symbol.hasInstance]-Methode hat noch aufrufbar ist. - Eine eigene
hasInstance-Logik kann dem Verhalten voninstanceofwidersprechen, das andere Entwickler erwarten, etwa beim Abgleich mitObject.getPrototypeOf. Nutze sie sparsam und dokumentiere sie. - Die Methode läuft bei jeder
instanceof-Prüfung. Aufwendige Prüfungen in häufig durchlaufenem Code können daher Leistung kosten. - Kompatibilität: Unterstützt in allen modernen Browsern (Baseline) und in Node.js ab Version 6.5. Im Internet Explorer gibt es sie nicht, und Transpiler können sie nicht vollständig nachbilden.