Symbol

Baseline Widely available

This feature is well established and works across many devices and browser versions. It’s been available across browsers since September 2015.

Symbol ist ein eingebautes Objekt, dessen Konstruktor ein symbol Primitiv zurückgibt — auch als Symbolwert oder einfach Symbol bezeichnet — das garantiert eindeutig ist. Symbole werden oft verwendet, um Objekten eindeutige Eigenschaftsschlüssel hinzuzufügen, die nicht mit Schlüsseln kollidieren, die anderer Code möglicherweise zu dem Objekt hinzufügt, und die von Mechanismen verborgen sind, die anderer Code typischerweise verwendet, um auf das Objekt zuzugreifen. Dies ermöglicht eine Form der schwachen Kapselung oder eine schwache Form der Informationsverbergung.

Jeder Symbol()-Aufruf garantiert die Rückgabe eines eindeutigen Symbols. Jeder Symbol.for("key")-Aufruf wird immer das gleiche Symbol für einen gegebenen Wert von "key" zurückgeben. Wenn Symbol.for("key") aufgerufen wird und ein Symbol mit dem angegebenen Schlüssel im globalen Symbolregister gefunden werden kann, wird dieses Symbol zurückgegeben. Andernfalls wird ein neues Symbol erstellt, im globalen Symbolregister unter dem angegebenen Schlüssel hinzugefügt und zurückgegeben.

Beschreibung

Um ein neues primitives Symbol zu erstellen, schreiben Sie Symbol() mit einem optionalen String als Beschreibung:

js
const sym1 = Symbol();
const sym2 = Symbol("foo");
const sym3 = Symbol("foo");

Der obige Code erstellt drei neue Symbole. Beachten Sie, dass Symbol("foo") den String "foo" nicht in ein Symbol umwandelt. Es wird jedes Mal ein neues Symbol erstellt:

js
Symbol("foo") === Symbol("foo"); // false

Die folgende Syntax mit dem new-Operator wird einen TypeError auslösen:

js
const sym = new Symbol(); // TypeError

Dies verhindert, dass Entwickler ein explizites Symbol-Wrapper-Objekt anstelle eines neuen Symbolwerts erstellen können, und kann überraschend sein, da das Erstellen expliziter Wrapper-Objekte um primitive Datentypen im Allgemeinen möglich ist (zum Beispiel new Boolean, new String und new Number).

Wenn Sie wirklich ein Symbol-Wrapper-Objekt erstellen möchten, können Sie die Object()-Funktion verwenden:

js
const sym = Symbol("foo");
typeof sym; // "symbol"
const symObj = Object(sym);
typeof symObj; // "object"

Da Symbole der einzige primitive Datentyp mit Referenzidentität sind (das heißt, Sie können dasselbe Symbol nicht zweimal erstellen), verhalten sie sich in gewisser Weise wie Objekte. Zum Beispiel sind sie speicherbereinigbar und können daher in WeakMap, WeakSet, WeakRef, und FinalizationRegistry-Objekten gespeichert werden.

Geteilte Symbole im globalen Symbolregister

Die obige Syntax mit der Symbol()-Funktion erstellt ein Symbol, dessen Wert während der gesamten Programmlaufzeit einzigartig bleibt. Um Symbole zu erstellen, die über Dateien und sogar über verschiedene Reiche (von denen jedes seinen eigenen globalen Geltungsbereich hat) verfügbar sind, verwenden Sie die Methoden Symbol.for() und Symbol.keyFor(), um Symbole aus dem globalen Symbolregister festzulegen und abzurufen.

Beachten Sie, dass das "globale Symbolregister" nur ein fiktives Konzept ist und möglicherweise keiner internen Datenstruktur in der JavaScript-Engine entspricht – und selbst wenn ein solches Register existiert, ist dessen Inhalt für den JavaScript-Code nicht verfügbar, außer über die Methoden for() und keyFor().

Die Methode Symbol.for(tokenString) nimmt einen String-Schlüssel und gibt einen Symbolwert aus dem Register zurück, während Symbol.keyFor(symbolValue) einen Symbolwert nimmt und den dem Symbolwert entsprechenden String-Schlüssel zurückgibt. Jede ist das Inverse der anderen, sodass das Folgende true ist:

js
Symbol.keyFor(Symbol.for("tokenString")) === "tokenString"; // true

Da registrierte Symbole willkürlich überall erstellt werden können, verhalten sie sich fast genauso wie die Strings, die sie umhüllen. Daher sind sie nicht garantiert einzigartig und nicht speicherbereinigbar. Daher sind registrierte Symbole in WeakMap, WeakSet, WeakRef, und FinalizationRegistry-Objekten nicht erlaubt.

Bekannte Symbole

Alle statischen Eigenschaften des Symbol-Konstruktors sind selbst Symbole, deren Werte über Reiche hinweg konstant sind. Sie sind als bekannte Symbole bekannt und dienen als "Protokolle" für bestimmte eingebauten JavaScript-Operationen, sodass Benutzer das Verhalten der Sprache anpassen können. Wenn zum Beispiel eine Konstruktorfunktion eine Methode mit Symbol.hasInstance als Namen hat, wird mit dieser Methode das Verhalten mit dem instanceof-Operator kodiert.

Vor den bekannten Symbolen verwendete JavaScript normale Eigenschaften, um bestimmte eingebaute Operationen zu implementieren. Zum Beispiel wird die Funktion JSON.stringify versuchen, die toJSON()-Methode jedes Objekts aufzurufen, und die Funktion String wird die toString()- und valueOf()-Methoden des Objekts aufrufen. Da jedoch mehr Operationen zur Sprache hinzugefügt werden, kann das Erstellen jeder Operation als "magische Eigenschaft" die Abwärtskompatibilität brechen und das Verhalten der Sprache schwerer nachvollziehbar machen. Bekannte Symbole ermöglichen es, dass die Anpassungen vom normalen Code "unsichtbar" sind, der typischerweise nur String-Eigenschaften liest.

Hinweis: Die Spezifikation verwendete früher die Notation @@<symbol-name>, um bekannte Symbole zu kennzeichnen. Zum Beispiel wurde Symbol.hasInstance als @@hasInstance geschrieben, und die Methode Array.prototype[Symbol.iterator]() würde als Array.prototype[@@iterator]() bezeichnet werden. Diese Notation wird in der Spezifikation nicht mehr verwendet, aber Sie könnten sie noch in älteren Dokumentationen oder Diskussionen sehen.

Bekannte Symbole haben nicht das Konzept der Speicherbereinigung, da sie in einer festen Anzahl vorkommen und während der gesamten Programmlaufzeit einzigartig sind, ähnlich wie intrinsische Objekte wie Array.prototype, sodass sie auch in WeakMap, WeakSet, WeakRef, und FinalizationRegistry-Objekten erlaubt sind.

Symbol-Eigenschaften auf Objekten finden

Die Methode Object.getOwnPropertySymbols() gibt ein Array von Symbolen zurück und ermöglicht es Ihnen, Symbol-Eigenschaften auf einem bestimmten Objekt zu finden. Beachten Sie, dass jedes Objekt mit keinen eigenen Symbol-Eigenschaften initialisiert wird, sodass dieses Array leer bleibt, es sei denn, Sie haben dem Objekt Symbol-Eigenschaften zugewiesen.

Konstruktor

Symbol()

Gibt primitive Werte des Typs Symbol zurück. Löst einen Fehler aus, wenn mit new aufgerufen.

Statische Eigenschaften

Die statischen Eigenschaften sind alle bekannte Symbole. In den Beschreibungen dieser Symbole werden wir Formulierungen verwenden wie "Symbol.hasInstance ist eine Methode, die bestimmt…", beachten Sie jedoch, dass dies sich auf die Semantik einer Methode eines Objekts bezieht, das dieses Symbol als Methodennamen hat (da bekannte Symbole als "Protokolle" fungieren), nicht auf den Wert des Symbols selbst.

Symbol.asyncIterator

Eine Methode, die den Standard-AsyncIterator für ein Objekt zurückgibt. Wird von for await...of verwendet.

Symbol.hasInstance

Eine Methode, die bestimmt, ob ein Konstruktorobjekt ein Objekt als Instanz erkennt. Wird von instanceof verwendet.

Symbol.isConcatSpreadable

Ein Boolean-Wert, der angibt, ob ein Objekt auf seine Array-Elemente abgeflacht werden soll. Wird von Array.prototype.concat() verwendet.

Symbol.iterator

Eine Methode, die den Standard-Iterator für ein Objekt zurückgibt. Wird von for...of verwendet.

Symbol.match

Eine Methode, die gegen einen String verwendet wird, auch um zu bestimmen, ob ein Objekt als regulärer Ausdruck verwendet werden kann. Wird von String.prototype.match() verwendet.

Symbol.matchAll

Eine Methode, die einen Iterator zurückgibt, der Übereinstimmungen des regulären Ausdrucks gegen einen String liefert. Wird von String.prototype.matchAll() verwendet.

Symbol.replace

Eine Methode, die übereinstimmende Teilstrings eines Strings ersetzt. Wird von String.prototype.replace() verwendet.

Symbol.search

Eine Methode, die den Index innerhalb eines Strings zurückgibt, der dem regulären Ausdruck entspricht. Wird von String.prototype.search() verwendet.

Symbol.species

Eine Konstruktionsfunktion, die verwendet wird, um abgeleitete Objekte zu erstellen.

Symbol.split

Eine Methode, die einen String an den Indizes aufteilt, die einem regulären Ausdruck entsprechen. Wird von String.prototype.split() verwendet.

Symbol.toPrimitive

Eine Methode, die ein Objekt in einen primitiven Wert umwandelt.

Symbol.toStringTag

Ein String-Wert, der für die Standardbeschreibung eines Objekts verwendet wird. Wird von Object.prototype.toString() verwendet.

Symbol.unscopables

Ein Objektwert, dessen eigene und geerbte Eigenschaftsnamen von den with-Umgebungsbindungen des zugeordneten Objekts ausgeschlossen sind.

Statische Methoden

Symbol.for()

Sucht nach vorhandenen registrierten Symbolen im globalen Symbolregister mit dem gegebenen Schlüssel und gibt es zurück, wenn es gefunden wird. Andernfalls wird ein neues Symbol erstellt und mit Schlüssel registriert.

Symbol.keyFor()

Ruft einen gemeinsamen Symbolschlüssel aus dem globalen Symbolregister für das gegebene Symbol ab.

Instanzeigenschaften

Diese Eigenschaften sind auf Symbol.prototype definiert und werden von allen Symbol-Instanzen geteilt.

Symbol.prototype.constructor

Die Konstruktionsfunktion, die das Instanzobjekt erstellt hat. Für Symbol-Instanzen ist der anfängliche Wert der Symbol-Konstruktor.

Symbol.prototype.description

Ein schreibgeschützter String, der die Beschreibung des Symbols enthält.

Symbol.prototype[Symbol.toStringTag]

Der anfängliche Wert der [Symbol.toStringTag]-Eigenschaft ist der String "Symbol". Diese Eigenschaft wird in Object.prototype.toString() verwendet. Da Symbol jedoch auch seine eigene toString()-Methode hat, wird diese Eigenschaft nicht verwendet, es sei denn, Sie rufen Object.prototype.toString.call() mit einem Symbol als thisArg auf.

Instanzmethoden

Symbol.prototype.toString()

Gibt einen String zurück, der die Beschreibung des Symbols enthält. Überschreibt die Object.prototype.toString()-Methode.

Symbol.prototype.valueOf()

Gibt das Symbol zurück. Überschreibt die Object.prototype.valueOf()-Methode.

Symbol.prototype[Symbol.toPrimitive]()

Gibt das Symbol zurück.

Beispiele

Verwendung des typeof Operators mit Symbolen

Der typeof-Operator kann Ihnen helfen, Symbole zu identifizieren.

js
typeof Symbol() === "symbol";
typeof Symbol("foo") === "symbol";
typeof Symbol.iterator === "symbol";

Symbol-Typumwandlungen

Einige Dinge zu beachten, wenn Sie mit der Typumwandlung von Symbolen arbeiten.

  • Wenn Sie versuchen, ein Symbol in eine Zahl umzuwandeln, wird ein TypeError ausgelöst (z. B. +sym oder sym | 0).
  • Bei Verwendung der losen Gleichheit gibt Object(sym) == sym true zurück.
  • Symbol("foo") + "bar" löst einen TypeError aus (kann Symbol nicht in String umwandeln). Dies verhindert, dass Sie beispielsweise unbemerkt einen neuen String-Eigenschaftsnamen aus einem Symbol erstellen.
  • Die "sicherere" String(sym)-Umwandlung funktioniert wie ein Aufruf von Symbol.prototype.toString() mit Symbolen, aber beachten Sie, dass new String(sym) einen Fehler auslöst.

Symbole und for...in Iteration

Symbole sind in for...in-Iterationen nicht aufzählbar. Außerdem wird Object.getOwnPropertyNames() keine Symbolobjekteigenschaften zurückgeben, jedoch können Sie Object.getOwnPropertySymbols() verwenden, um diese zu erhalten.

js
const obj = {};

obj[Symbol("a")] = "a";
obj[Symbol.for("b")] = "b";
obj["c"] = "c";
obj.d = "d";

for (const i in obj) {
  console.log(i);
}
// "c" "d"

Symbole und JSON.stringify()

Symbol-gekoppelte Eigenschaften werden beim Verwenden von JSON.stringify() vollständig ignoriert:

js
JSON.stringify({ [Symbol("foo")]: "foo" });
// '{}'

Für weitere Details siehe JSON.stringify().

Symbol-Wrapper-Objekte als Eigenschaftsschlüssel

Wenn ein Symbol-Wrapper-Objekt als Eigenschaftsschlüssel verwendet wird, wird dieses Objekt zu seinem umschlossenen Symbol umgewandelt:

js
const sym = Symbol("foo");
const obj = { [sym]: 1 };
obj[sym]; // 1
obj[Object(sym)]; // still 1

Spezifikationen

Specification
ECMAScript Language Specification
# sec-symbol-objects

Browser-Kompatibilität

BCD tables only load in the browser

Siehe auch