W3docs

JavaScript Symbol-Typ

Lerne den JavaScript Symbol-Typ: eindeutige Werte erstellen, Symbole als versteckte Objektschlüssel, die globale Registry mit Symbol.for und Symbol.keyFor sowie bekannte Symbole wie Symbol.iterator.

Einführung in JavaScript-Symbole

Symbole, eingeführt in ECMAScript 2015 (ES6), sind ein einzigartiger und unveränderlicher Datentyp, der hauptsächlich dazu verwendet wird, einzigartige Property-Schlüssel zu Objekten hinzuzufügen. Dieser Leitfaden erkundet Symbole, ihre praktischen Anwendungen und wie sie die JavaScript-Entwicklung durch eindeutige Bezeichner und Metaprogrammierungsfähigkeiten bereichern.

Symbole verstehen

Ein Symbol ist ein einzigartiger und unveränderlicher primitiver Wert, der als Schlüssel einer Objekt-Eigenschaft verwendet werden kann. Jeder von Symbol() zurückgegebene Symbolwert ist von allen anderen verschieden, was seine Einzigartigkeit garantiert.

Beispiel: Symbole erstellen und verwenden

javascript— editable

sym1 wird ohne Beschreibung erstellt, während sym2 und sym3 mit derselben Beschreibung erstellt werden. Obwohl sie dieselbe Beschreibung haben, sind sym2 und sym3 eindeutige Symbole.

Bitte beachte, dass in diesem Beispiel die Funktion String() verwendet wird, um die Symbole zur sicheren Ausgabe in ein Stringformat umzuwandeln.

Symbole als Property-Schlüssel

Die Verwendung von Symbolen als Property-Schlüssel ermöglicht es, „versteckte" Eigenschaften hinzuzufügen, die bei der gewöhnlichen Aufzählung ignoriert werden. Eine symbol-basierte Eigenschaft wird von for...in, Object.keys() und JSON.stringify() übersprungen. Genau das macht Symbole nützlich zum Speichern von Metadaten, die nicht in die serialisierte Ausgabe oder in unbeabsichtigte Schleifen gelangen sollen. Um Symbol-Schlüssel wieder auszulesen, verwendet man Object.getOwnPropertySymbols() oder Reflect.ownKeys() (Letzteres gibt sowohl string- als auch symbol-basierte Schlüssel zurück). Die eigenen Attribute einer Symbol-Eigenschaft — writable, enumerable, configurable — lassen sich mit Object.defineProperty() genauso steuern wie bei einem String-Schlüssel (siehe Property-Flags und Deskriptoren).

Um ein Symbol als Schlüssel in einem Objekt-Literal zu verwenden, wird es in eckige Klammern eingeschlossen: [id]. Ohne die Klammern würde das Literal einen regulären String-Schlüssel namens "id" erstellen.

Beispiel: Symbole werden bei der Aufzählung übersprungen

javascript— editable

Das user-Objekt speichert 123 unter einem Symbol-Schlüssel, den man nur lesen kann, wenn man das ursprüngliche id-Symbol besitzt. Da Object.keys, for...in und JSON.stringify es alle ignorieren, bleibt der Wert aus serialisierten Payloads und generischen Property-Schleifen verborgen — jedoch ist er nicht wirklich privat: Jeder, der Object.getOwnPropertySymbols kennt, kann ihn noch entdecken.

Symbole teilen mit Symbol.for und Symbol.keyFor

Mit Symbol.for erstellte Symbole werden in der globalen Symbol-Registry gespeichert und können überall im Code abgerufen werden, was konsistente Referenzen durch die Methoden Symbol.for und Symbol.keyFor gewährleistet.

Beispiel: Symbole teilen

javascript— editable

Der wesentliche Unterschied zu Symbol(): Symbol.for(key) führt eine globale, realm-übergreifende Tabelle mit String-Schlüsseln. Wird es zweimal mit demselben Schlüssel aufgerufen, gibt es dasselbe Symbol zurück — auch aus verschiedenen Dateien oder Modulen. Das ist nützlich, wenn unabhängige Teile einer App auf ein gemeinsames Symbol angewiesen sind, ohne es voneinander importieren zu müssen. Symbol.keyFor führt die umgekehrte Suche durch, aber nur für Registry-Symbole; für ein reguläres Symbol() gibt es undefined zurück.

Praxisbeispiele

Hier sind einige praktische Beispiele, wie Symbole in realen Szenarien eingesetzt werden können:

1. Zugriff auf Objekt-Eigenschaften verwalten

Symbole sind besonders nützlich, wenn der Zugriff auf bestimmte Eigenschaften eines Objekts kontrolliert werden soll, um sicherzustellen, dass sie nicht versehentlich über gängige Methoden zum Zugriff auf Objekt-Eigenschaften geändert oder abgerufen werden.

Beispiel: Private Member in Klassen

Beim Erstellen von Klassen in JavaScript möchte man möglicherweise private Eigenschaften haben, auf die außerhalb der Klassenmethoden nicht direkt zugegriffen werden soll. Die Verwendung von Symbolen kann eine Form von Privatheit ermöglichen.

javascript— editable

2. Property-Kollisionen vermeiden

Beim Arbeiten mit Mixins oder beim Erweitern von Objekten, bei denen nicht alle Property-Namen kontrolliert werden können, helfen Symbole dabei, Namenskollisionen zu vermeiden.

Beispiel: Sichere Mixins

Wenn ein Objekt mit zusätzlicher Funktionalität aus mehreren Quellen erweitert wird, können Symbole sicherstellen, dass es keine Schlüsselkollisionen gibt, die vorhandene Eigenschaften überschreiben könnten.

javascript— editable

3. Metaprogrammierung

Symbole sind ein wesentlicher Bestandteil der Metaprogrammierungsfähigkeiten von JavaScript. Bestimmte bekannte Symbole werden verwendet, um das Verhalten von Objektinstanzen zu ändern oder anzupassen. Neben Symbol.iterator bieten weitere wie Symbol.toStringTag (passt die Ausgabe von Object.prototype.toString an) und Symbol.hasInstance (passt das instanceof-Verhalten an) eine tiefe Sprachintegration.

Beispiel: Benutzerdefinierte Iteratoren

Mithilfe von Symbolen kann benutzerdefiniertes Iterations-Verhalten auf Objekten über die Eigenschaft Symbol.iterator definiert werden.

javascript— editable

4. Symbole zum Debuggen

Symbole können auch zu Debugging-Zwecken nützlich sein, da Metainformationen an Objekte angehängt werden können, ohne ihr Betriebsverhalten zu beeinflussen.

Beispiel: Debug-Informationen hinzufügen

javascript— editable

Diese Beispiele veranschaulichen, wie Symbole in praktischen Szenarien eingesetzt werden können, um Objekt-Eigenschaften sicherer zu verwalten, Funktionalität ohne Konflikte zu erweitern und fortgeschrittene Programmiertechniken in JavaScript zu ermöglichen.

Bekannte Symbole

JavaScript definiert eine Reihe von „bekannten" Symbolen direkt am Symbol-Objekt vor — zum Beispiel Symbol.iterator, Symbol.toPrimitive, Symbol.toStringTag und Symbol.hasInstance. Diese befinden sich nicht in der globalen Registry; sie sind feste Hooks, die die Sprache zu bestimmten Zeitpunkten konsultiert. Wird eines davon am eigenen Objekt implementiert, lässt sich das eingebaute Verhalten anpassen.

Primitive Konvertierung mit Symbol.toPrimitive anpassen

Wenn ein Objekt dort verwendet wird, wo ein primitiver Wert erwartet wird — String-Interpolation, Arithmetik, Vergleiche —, ruft JavaScript die Methode Symbol.toPrimitive des Objekts auf (sofern vorhanden) und übergibt einen hint von "string", "number" oder "default". Das bietet eine zentrale Stelle zur Steuerung jeder Typumwandlung, anstatt toString und valueOf separat zu überschreiben. Den vollständigen Regelsatz findet man unter Objekt-zu-Primitiv-Konvertierung.

javascript— editable

Da die Konvertierungslogik hinter einem Symbol-Schlüssel liegt, kollidiert sie nie mit eigenen Dateneigenschaften und erscheint nie in JSON.stringify.

Fazit

Symbole in JavaScript bieten eine robuste Möglichkeit, eindeutige Bezeichner zu verwalten und Entwicklern zu ermöglichen, Objekt-Eigenschaften mit einem hohen Maß an Kontrolle und Privatheit zu handhaben. Durch die Verwendung von Symbolen kann sichergestellt werden, dass Eigenschaften auf angemessene Weise verwendet werden und unbeabsichtigte Nebeneffekte vermieden werden.

Übungen

Übung
Was sind einige Merkmale des JavaScript Symbol-Typs?
Was sind einige Merkmale des JavaScript Symbol-Typs?
Was this page helpful?