Hier ist, wie ich Symbole aus meiner Sicht beschreiben würde, und auch warum ich sie für nutzlosen Müll halte:
Kurze Erklärung:
Symbole sind das JavaScript-Äquivalent von eingebauten, eindeutigen enum
erationswerten mit einem "Beschreibungs"-String, der keinen Einfluss auf den Wert oder die Einzigartigkeit des Symbols hat. Aber das Verhalten ändert sich wesentlich, je nachdem, ob du Symbol()
oder Symbol.for()
benutzt!!!
Wie andere bereits festgestellt haben:
mySymbol = Symbol("blau");
mySymbol.description //"blau"
mySymbol == mySymbol //true
//Anders als du vielleicht erwarten würdest...
mySymbol != Symbol("blau")
//Also, Symbol() erstellt jedes Mal ein neues Symbol.
Symbol("blau") != Symbol("blau")
Siehe auch zum Thema Aufzählung von Objekten, die Symbole enthalten:
Problem Eins...
Das mag für dich bisher in Ordnung und funktionstüchtig erscheinen, bis du entdeckst, was Symbol.for()
ist...:
Die statische Methode Symbol.for()
sucht nach vorhandenen Symbolen im symbolübergreifenden Symbolregister mit dem angegebenen Schlüssel und gibt es zurück, wenn es gefunden wird. Andernfalls wird ein neues Symbol im globalen Symbolregister mit diesem Schlüssel erstellt.
a = Symbol("blau");
a.description //"blau"
b = Symbol("blau");
c = Symbol.for("blau");
c.description //"blau"
d = Symbol.for("blau");
a != b //Das wissen wir bereits, aber dann...
a != c //Oh? Also sind sie unterschiedlich. Ja!
//Aber vielleicht ist es das neueste...?
b != c //Nein!
b != d //Auch nicht!
c == d //Dies ist die EINZIGE Permutation, die äquivalent ist.
Also, während Symbol()
ein Symbol mit einem völlig wert- und eindeutigkeitsunabhängigen "Beschreibungs"-String erstellt, erstellt Symbol.for()
ein Symbol mit einem weltweit zugeordneten "Beschreibungs"-String.... Aber, weil der "Beschreibungs"-String von Symbol()
irrelevant ist, arbeiten Symbol()
und Symbol.for()
in zwei völlig getrennten Welten, obwohl sie denselben Symboltyp und ähnliche Terminologie verwenden ...!
Sehr klar, danke JavaScript-Herrscher!
Weitere Probleme...
Um es zu verdeutlichen, hier ist, warum Symbole nutzlos sind...:
-
Angenommen, du stößt auf ein Symbol
. Du musst dies verwenden, um zur Laufzeit zu bestimmen, welche Methode der Symbolerstellung verwendet wurde:
//Methode A: Symbol()
Symbol.keyFor(Symbol("blau")) //undefined
//Methode B: Symbol.for()
Symbol.keyFor(Symbol.for("blau")) //blau
-
Wenn sie Methode A verwendet haben und du sie verwenden möchtest, solltest du hoffen, dass dein Code Zugriff auf genau diesen Symbolschlüssel hat...
-
Wenn sie Methode B verwendet haben, solltest du hoffen, dass kein anderer Code in deinem Codebestand diesen Symbolschlüssel verwendet, da er global ist...
-
Die Hauptidee hinter der Verwendung von Symbolen besteht darin, Kollisionen von Namen/Schlüsseln zu vermeiden, z. B. in zukünftigem Code... aber wie ist das besser als die bereits vorhandenen Typen?
-
Manche würden diese Frage wohl damit beantworten, dass Symbole nicht wie die anderen Typen aufgezählt werden (siehe Links aus früheren Antworten). Okay? Und wie hilft das? Verwende einfach Object.defineProperty()
und setze enumerable
auf false
. Alles, was Symbole tun, ist, unnötige Komplikationen in die Sprache zu bringen, weil du jetzt etwas anderes wie Reflect.ownKeys()
verwenden musst, um auf alle Eigenschaften eines Objekts zuzugreifen... Wie MDN sagt...:
[Reflect.ownKeys()
] ist der einzige Weg, um alle eigenen Eigenschaften – aufzählbar und nicht aufzählbar, Zeichenfolgen und Symbole — in einem Aufruf zu erhalten, ohne zusätzliche Filterlogik. Beispielsweise nimmt Object.getOwnPropertyNames()
den Rückgabewert von Reflect.ownKeys()
und filtert nur Zeichenfolgenwerte, während Object.getOwnPropertySymbols()
nur Symbolwerte filtert.
-
Sie rühmen sich damit, dass Symbole nicht verändert oder Eigenschaften auf sie zugewiesen werden können (und somit auch nicht erneut zugewiesen werden können) (was bereits mit einfachen JS-Zeichenfolgen oder auch Object.freeze()
möglich ist...), aber das ist eher ein Hindernis als ein Feature. Du möchtest vielleicht etwas wie das hier tun:
myEnum = [
{ name: "blau" },
{ name: "rot" }
];
//Das geht nicht mit Symbolen...:
for (let index = 0; index < myEnum.length; ++index) {
myEnum[index].value = index;
}
/
was es zu folgendem machen würde:
myEnum = [
{ name: "blau", value: 0 },
{ name: "rot", value: 1 }
];
/
-
Symbol()
akzeptiert andere Arten von Beschreibungen (oder nichts) in seiner Konstruktionsfunktion (die kein new
verwendet...), aber es stringifiziert, was du auch immer hineinsteckst, z. B.:
Symbol({ val: 5 }).description == "[object Object]"
Also nützlich!
Schlussfolgerung
Also, mein Rat? Verwende Symbole überhaupt nicht, wenn du es vermeiden kannst. Verwende einfache {}
Objekte, class
-Klassen, []
Arrays, Zeichenfolgen, Zahlen - praktisch alles andere - stattdessen. Anstatt dass JS Enums einfacher macht wie sie es sollten, haben sie diesen komplizierten und mehr nutzlos als nützlichen Symbolmüll hinzugefügt.