Signatur
Beschreibung
Symbol.for() greift auf das globale Symbol-Register zu, das in der gesamten Laufzeitumgebung gilt. Gibt es dort schon ein Symbol mit dem angegebenen Schlüssel, bekommst du genau dieses Symbol zurück. Gibt es noch keins, wird ein neues angelegt, unter dem Schlüssel eingetragen und zurückgegeben. Mehrere Aufrufe mit demselben Schlüssel liefern also immer dasselbe Symbol.
Darin liegt der Unterschied zu Symbol(): Jeder Aufruf von Symbol("x") erzeugt ein neues, einzigartiges Symbol. Die Beschreibung dient dabei nur zur Fehlersuche. Symbol.for("x") ist dagegen idempotent. Das Register gilt sogar über Realm-Grenzen hinweg, zum Beispiel zwischen iframes, Web Workern mit eigenem Realm oder vm-Kontexten in Node.js.
Typische Einsatzgebiete sind gemeinsame Protokoll-Schlüssel zwischen Modulen, Bibliotheken oder mehrfach geladenen Paketversionen. So markiert React seine Elemente zum Beispiel mit Symbol.for("react.element"). Auch Node.js nutzt Symbol.for("nodejs.util.inspect.custom") für eigene Ausgaben in console.log. Mit Symbol.keyFor() findest du zu einem registrierten Symbol den Schlüssel wieder.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $key Pflicht | string | "undefined" | Schlüssel, unter dem das Symbol im Register steht. Er dient gleichzeitig als Beschreibung des Symbols. Andere Werte werden in einen String umgewandelt. Ohne Argument wird daraus der String "undefined". |
Rückgabewert
Beispiele
Symbol.for() im Vergleich zu Symbol()
const a = Symbol.for("app.id");
const b = Symbol.for("app.id");
console.log(a === b); // gleiches Symbol aus dem Register
const c = Symbol("app.id");
console.log(a === c); // Symbol() erzeugt immer ein neues Symbol
console.log(a.description);
console.log(Symbol.keyFor(a)); // Schlüssel eines registrierten Symbols
console.log(Symbol.keyFor(c)); // nicht registriert
Gemeinsamer Protokoll-Schlüssel zwischen Modulen
// modul-a.js: markiert Objekte als serialisierbar
const SERIALIZE = Symbol.for("meinprojekt.serialize");
export class User {
constructor(name) { this.name = name; }
[SERIALIZE]() { return JSON.stringify({ typ: "user", name: this.name }); }
}
// modul-b.js: braucht keinen Import des Symbols
export const serialize = (obj) => {
const fn = obj[Symbol.for("meinprojekt.serialize")];
return typeof fn === "function" ? fn.call(obj) : JSON.stringify(obj);
};
// Verwendung
// console.log(serialize(new User("Anna")));
Eigene Ausgabe für console.log in Node.js
const inspect = Symbol.for("nodejs.util.inspect.custom");
class Geld {
constructor(betrag) { this.betrag = betrag; }
[inspect]() { return `Geld(${this.betrag.toFixed(2)} €)`; }
}
console.log(new Geld(19.9));
// Wichtig · Fallstricke
- Kein Schutz vor Namenskonflikten: Das Register ist global. Wenn zwei Bibliotheken zufällig denselben Schlüssel verwenden, teilen sie sich das Symbol. Nutze deshalb Schlüssel mit Namensraum, zum Beispiel
"firma.paket.zweck". - Nicht privat: Jeder Code kann mit demselben Schlüssel an das Symbol kommen. Registrierte Symbole taugen nicht dazu, Daten zu verbergen. Dafür gibt es private Klassenfelder (
#feld) oderWeakMap. - Registrierte Symbole kann die Speicherbereinigung nicht entfernen. Sie sind deshalb auch nicht als Schlüssel in
WeakMap/WeakSeterlaubt (ES2023, führt zuTypeError). Nicht registrierte Symbole ausSymbol()sind dort dagegen zulässig. - Bekannte Symbole wie
Symbol.iteratorstehen nicht im Register:Symbol.keyFor(Symbol.iterator)ergibtundefined. - Der Schlüssel wird in einen String umgewandelt:
Symbol.for(1) === Symbol.for("1")ergibttrue. - Kompatibilität: wird seit ES2015 von allen modernen Browsern und Node.js unterstützt, aber nicht vom Internet Explorer.