428 Stimmen

Was ist die Motivation, Symbole nach ES6 zu bringen?

UPDATE: Vor kurzem wurde ein brillanter Artikel von Mozilla veröffentlicht. Lesen Sie ihn, wenn Sie neugierig sind.

Wie Sie vielleicht wissen, planen sie, einen neuen Symbol-Primitivtyp in ECMAScript 6 aufzunehmen (um nicht zu erwähnen, einige andere verrückte Sachen). Ich habe immer gedacht, dass die :symbol -Notation in Ruby unnötig ist; wir könnten problemlos einfache Zeichenfolgen verwenden, wie wir es in JavaScript tun. Und jetzt entscheiden sie sich, die Dinge in JS mit diesem Symbol zu komplizieren.

Ich verstehe die Motivation nicht. Könnte mir jemand erklären, ob wir wirklich Symbole in JavaScript brauchen?

3voto

Willem van der Veen Punkte 26043

Ein JS-Symbol ist ein neuer primitiver Datentyp. Sie sind Token, die als eindeutige IDs dienen. Ein Symbol kann mit dem Symbol-Konstruktor erstellt werden. Sehen Sie sich beispielsweise diesen Auszug von MDN an:

// Der Symbol-Konstruktor nimmt ein optionales Argument an, 
// die Beschreibung, die nur für Debugging-Zwecke verwendet wird.
// Hier sind zwei Symbole mit der gleichen Beschreibung
let Sym1 = Symbol("Sym");
let Sym2 = Symbol("Sym");

console.log(Sym1 == Sym2); // gibt "false" zurück
// Symbole sind garantiert eindeutig.
// Auch wenn wir viele Symbole mit derselben Beschreibung erstellen,
// handelt es sich um unterschiedliche Werte.

Oft ist es praktisch, Symbole als eindeutige Objekteigenschaftsschlüssel zu verwenden, beispielsweise:

let obj = {};
let prop = Symbol();

obj[prop] = 123;  // das Symbol prop wird mit 123 zugewiesen
obj.prop  = 456;  // das Zeichenfolgenprop wird mit 456 zugewiesen

console.log(obj.prop, obj[prop]); // gibt 456, 123 aus

1voto

Andrew Punkte 4502

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 enumerationswerten 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.

0voto

snr Punkte 15782

Die Symbole haben zwei Hauptanwendungsfälle:

  1. „Versteckte“ Objekteigenschaften. Wenn wir einer Eigenschaft ein Objekt hinzufügen möchten, das „gehört“ zu einem anderen Skript oder einer Bibliothek, können wir ein Symbol erstellen und es als Eigenschaftsschlüssel verwenden. Eine symbolische Eigenschaft erscheint nicht in for..in, sodass sie nicht versehentlich zusammen mit anderen Eigenschaften verarbeitet wird. Außerdem wird sie nicht direkt abgerufen, weil ein anderes Skript unser Symbol nicht hat. Die Eigenschaft wird also vor versehentlicher Verwendung oder Überschreibung geschützt.

    Daher können wir „heimlich“ etwas in Objekten verstecken, das wir benötigen, aber das andere nicht sehen sollen, indem wir symbolische Eigenschaften verwenden.

  2. Es gibt viele Systemsymbole, die von JavaScript verwendet werden und als Symbol.* zugänglich sind. Wir können sie verwenden, um einige eingebaute Verhaltensweisen zu ändern. Zum Beispiel ..... Symbol.iterator für Iterierbare, Symbol.toPrimitive für die Einrichtung von Objekt-zu-Primitiv-Konvertierungen und so weiter.

Quelle

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X