JavaScript instanceof
Der instanceof-Operator in JavaScript prüft, ob ein object zu einer bestimmten Klasse gehört, und unterstützt Typenprüfung sowie Polymorphismus.
Einführung in den instanceof-Operator
Der instanceof-Operator in JavaScript ist ein leistungsstarkes Werkzeug, um festzustellen, ob ein object eine Instanz einer bestimmten Klasse oder Konstruktorfunktion ist. Er hilft Entwicklern, den Typ eines object zur Laufzeit zu überprüfen, was Typenprüfung und die effektive Implementierung von Polymorphismus ermöglicht. Dieser Operator prüft die Prototypenkette eines object gegenüber dem Prototyp einer Konstruktorfunktion und liefert ein boolean-Ergebnis, das angibt, ob das object vom Prototyp erbt.
Syntax und Verwendung
Die Syntax des instanceof-Operators ist unkompliziert:
object instanceof ConstructorDabei ist object das object, das gegen den Constructor geprüft wird. Der Operator gibt true zurück, wenn das object eine Instanz des Constructor ist oder von ihm geerbt hat; andernfalls gibt er false zurück.
Codebeispiel: Grundlegende Verwendung
Betrachten Sie das folgende Beispiel, bei dem wir eine Klasse Vehicle definieren und eine Instanz davon erstellen:
Erweiterte Anwendungen
Über die grundlegende Typenprüfung hinaus spielt der instanceof-Operator in komplexeren Szenarien mit Vererbung und Polymorphismus eine wichtige Rolle. Sehen wir uns ein Szenario mit Vererbung an:
Codebeispiel: Vererbung
Dieses Beispiel zeigt, wie instanceof bestätigt, dass myCar nicht nur eine Instanz von Car, sondern auch eine Instanz von Vehicle ist – und damit die Fähigkeit des Operators demonstriert, die Vererbungskette zu erkennen.
Wie instanceof die Prototypenkette durchläuft
instanceof prüft nicht direkt, welcher Konstruktor das object erstellt hat. Stattdessen durchläuft es die Prototypenkette des object aufwärts und fragt: Kommt Constructor.prototype irgendwo darin vor? Sobald eine Übereinstimmung gefunden wird, gibt es true zurück; erreicht es das Ende der Kette (null) ohne Übereinstimmung, gibt es false zurück.
Deshalb können Sie ein instanceof-Ergebnis verändern, indem Sie die Prototypenkette neu zuweisen – die Prüfung dreht sich ausschließlich um die Kettenzugehörigkeit, nicht um den ausgeführten Konstruktor. Weitere Informationen zur Kette selbst finden Sie unter Prototypische Vererbung und Grundlegende Klassensyntax.
instanceof mit Symbol.hasInstance anpassen
Sie können überschreiben, was obj instanceof Constructor zurückgibt, indem Sie eine statische [Symbol.hasInstance]-Methode auf dem Konstruktor definieren. Wenn diese vorhanden ist, ruft instanceof sie mit dem linken Operanden auf und verwendet deren boolean-Ergebnis, wobei die Prototypenkette vollständig ignoriert wird.
Dies ist nützlich für Duck-Typing – also dafür, jedes object, das „richtig aussieht", als Member eines Typs zu behandeln –, ohne es durch die Klassenhierarchie zu zwingen.
instanceof vs. typeof vs. constructor
Diese drei Werkzeuge beantworten unterschiedliche Fragen, und die Wahl des falschen ist eine häufige Fehlerquelle.
typeofgibt einen string für primitive Typkategorien zurück. Es eignet sich gut für Primitive, gibt aber für fast alles"object"zurück (arrays,null, Datumsangaben, einfache objects), und kann daher keine object-Typen unterscheiden.instanceofprüft die Zugehörigkeit zur Prototypenkette und berücksichtigt Vererbung – schlägt aber über Realms hinweg fehl (siehe unten) und funktioniert nicht bei Primitiven.obj.constructorzeigt auf die Funktion, die das object erstellt hat, ist aber nur eine beschreibbare Eigenschaft und spiegelt nur die spezifischste Klasse wider, nicht die gesamte Kette.
Die oben verwendeten eingebauten Konstruktoren werden in Native Prototypen behandelt.
Die Realm-Problematik (iframe/window)
Jeder Browsing-Kontext – jedes iframe oder Popup-Fenster – verfügt über einen eigenen Satz eingebauter Konstruktoren sowie ein eigenes Array.prototype, Object.prototype usw. Ein array, das in einem iframe erstellt wurde, ist ein echtes array, erbt aber nicht vom Array.prototype Ihres Fensters. Daher gibt arrayFromIframe instanceof Array im übergeordneten Fenster false zurück, obwohl der Wert tatsächlich ein array ist. Dies ist der häufigste Grund, warum instanceof „lügt".
Für Werte, die möglicherweise Realm-Grenzen überschreiten, bevorzugen Sie realm-agnostische Prüfungen wie Array.isArray(value).
Zuverlässige Typ-Tags mit Object.prototype.toString
Wenn Sie eine robuste, realm-sichere Typenprüfung benötigen, die auch bei Primitiven funktioniert, gibt Object.prototype.toString einen internen Tag-string im Format [object Type] zurück. Er kann nicht durch neu zugewiesene Prototypen getäuscht werden wie constructor, und er funktioniert über Realms hinweg.
Verwenden Sie ihn über .call(value), damit der Wert zu this wird. Eine Klasse kann sogar ihr eigenes Tag mit der Symbol.toStringTag-Eigenschaft steuern.
Best Practices und Hinweise
Obwohl der instanceof-Operator äußerst wertvoll ist, sollte er mit Bedacht eingesetzt werden:
- Sensitivität der Prototypenkette: Der
instanceof-Operator stützt sich auf die Prototypenkette, was bedeutet, dass Änderungen am Prototyp eines object das Ergebnis voninstanceof-Prüfungen beeinflussen können. - Einsatz bei Polymorphismus: Er ist besonders nützlich in Szenarien, in denen polymorphes Verhalten gewünscht ist, da er flexiblen Code ermöglicht, der objects verschiedener Typen einheitlich verarbeiten kann.
- Cross-Frame-Probleme: Seien Sie vorsichtig bei der Verwendung von
instanceofmit objects aus verschiedenen JavaScript-Kontexten (z. B. iframes oder verschiedenen Fenstern), da jeder Kontext eine eigene Prototypenkette besitzt.
Praktisches Beispiel: Polymorphismus
So könnten Sie instanceof verwenden, um polymorphes Verhalten zu implementieren:
Fazit
Das Verstehen und effektive Einsetzen des instanceof-Operators ist entscheidend, um die objektorientierten Programmieraspekte von JavaScript zu meistern. Er hilft nicht nur bei der Typenprüfung und der Sicherstellung der Korrektheit Ihres Codes, sondern ermöglicht es Ihnen auch, durch Polymorphismus flexibleren und wartbareren Code zu schreiben. Indem Sie den instanceof-Operator sinnvoll in Ihre Entwicklungspraxis integrieren, können Sie die Robustheit und Skalierbarkeit Ihrer JavaScript-Anwendungen erheblich verbessern.