AKTUALIZACJA : Niedawno pojawił się genialny artykuł z Mozilli . Przeczytaj, jeśli jesteś ciekawy.
Jak zapewne wiesz, planują dołączyć nowy typ prymitywny Symbol do ECMAScript 6 (nie wspominając o innych zwariowanych rzeczach). Zawsze myślałem, że :symbol
pojęcie w Ruby jest niepotrzebne; zamiast tego moglibyśmy z łatwością używać zwykłych ciągów, tak jak w JavaScript. A teraz postanawiają to skomplikować w JS.
Nie rozumiem motywacji. Czy ktoś mógłby mi wyjaśnić, czy naprawdę potrzebujemy symboli w JavaScript?
private
ipublic
słowa kluczowe atrybutu klasy, którą postanowili porzucić w celu uproszczenia implementacji klasy. Zamiast tegothis.x = x
miałeś zrobićpublic x = x
i dla zmiennych prywatnychprivate y = y
. Zdecydowali się to porzucić, aby uzyskać znacznie bardziej minimalną implementację klasy. Symbol byłby wówczas wymaganym obejściem, aby uzyskać prywatne właściwości przy minimalnej implementacji.Odpowiedzi:
Oryginalną motywacją do wprowadzenia symboli do Javascript było włączenie własności prywatnych .
Niestety ostatecznie zostali poważnie obniżeni. Nie są już prywatne, ponieważ można je znaleźć przez odbicie, na przykład za pomocą
Object.getOwnPropertySymbols
lub proxy.Są one teraz znane jako unikalne symbole, a ich jedynym przeznaczeniem jest unikanie konfliktów nazw między właściwościami. Na przykład sam ECMAScript może teraz wprowadzać rozszerzenia za pomocą pewnych metod, które można umieszczać na obiektach (np. W celu zdefiniowania ich protokołu iteracji) bez ryzyka kolizji z nazwami użytkowników.
Czy jest to wystarczająco silna motywacja do dodania symboli do języka jest dyskusyjna.
źródło
Object.getOwnPropertySymbols
nie jest jedynym wyciekiem; tym trudniejsza jest możliwość korzystania z serwerów proxy w celu przechwycenia dostępu do „prywatnej” własności.Symbole nie gwarantują prawdziwej prywatności, ale można ich użyć do oddzielenia publicznych i wewnętrznych właściwości obiektów. Weźmy przykład, w którym możemy użyć
Symbol
do posiadania prywatnych nieruchomości.Weźmy przykład, w którym właściwość obiektu nie jest prywatna.
Powyżej
Pet
właściwość klasytype
nie jest prywatna. Aby uczynić go prywatnym, musimy stworzyć zamknięcie. Poniższy przykład ilustruje, w jaki sposób możemy uczynićtype
prywatnym za pomocą zamknięcia.Wada powyższego podejścia: Wprowadzamy dodatkowe zamknięcie dla każdej
Pet
utworzonej instancji, co może zaszkodzić wydajności.Teraz przedstawiamy
Symbol
. Może to pomóc nam uczynić nieruchomość prywatną bez użycia dodatkowych niepotrzebnych zamknięć. Przykład kodu poniżej:źródło
_
nie gwarantuje prawdziwej prywatności, ale może być użyte do oddzielenia publicznych i wewnętrznych właściwości obiektów. Innymi słowy, bezcelowa odpowiedź.Symbols
są nowym, specjalnym rodzajem obiektu, który może być używany jako unikalna nazwa właściwości w obiektach. UżycieSymbol
zamiaststring
„pozwala” na tworzenie różnych modułów, które nie powodują konfliktów między sobą.Symbols
można również ustawić jako prywatny, aby ich właściwości nie były dostępne dla osób, które nie mają jeszcze bezpośredniego dostępu doSymbol
.Symbols
są nowym prymitywem . Podobnie jaknumber
,string
iboolean
prymitywów,Symbol
posiada funkcję, która może być użyta do ich tworzenia. W przeciwieństwie do innych prymitywów,Symbols
nie używaj literalnej składni (np. Jak tostring
zrobić''
) - jedynym sposobem ich utworzenia jest użycieSymbol
konstruktora w następujący sposób:W rzeczywistości
Symbol
są tylko nieco innym sposobem dołączania właściwości do obiektu - możesz łatwo podać znaneSymbols
metody standardowe, tak jak toObject.prototype.hasOwnProperty
występuje we wszystkim, co dziedziczy poObject
.Oto niektóre z zalet
Symbol
pierwotnego typu.Symbols
mają wbudowaną możliwość debuggowaniaSymbols
można podać opis, który jest tak naprawdę używany do debugowania, aby ułatwić sobie życie podczas logowania do konsoli.Symbols
mogą być używane jakoObject
kluczeTo jest
Symbol
naprawdę interesujące. Są mocno splecione z przedmiotami.Symbol
można przypisać jako klucze do obiektów, co oznacza, że możesz przypisać nieograniczoną liczbę unikalnychSymbol
obiektów do obiektu i mieć pewność, że nigdy nie będą one kolidować zstring
kluczami lub innymi unikatowymiSymbols
.Symbols
może być użyty jako unikalna wartość.Załóżmy, że masz biblioteki rejestrowania, która obejmuje wiele poziomów dziennika, takich jak
logger.levels.DEBUG
,logger.levels.INFO
,logger.levels.WARN
i tak dalej. W kodzie ES5 chcesz ustawić testring
(taklogger.levels.DEBUG === 'debug'
) lubnumber
s (logger.levels.DEBUG === 10
). Oba nie są idealne, ponieważ te wartości nie są wartościami unikalnymi, aleSymbol
są! Pologger.levels
prostu staje się:Przeczytaj więcej w tym świetnym artykule .
źródło
log.levels = {DEBUG: Symbol('debug')
a nie po prostulog.levels = {DEBUG:'debug'}
. na koniec jest tak samo. Myślę, że warto wspomnieć, że symbole są niewidoczne podczas iteracji po kluczach obiektu. to jest ich „rzecz”{}
i osiągnąć ten sam wynik (jako unikalną wartość), a może literał jest preferowany w tym projekcie, lub możesz powiedzieć, że musisz najpierw przeczytać dokument.) osobiście uważam, że zapewnia dobrą czytelność unikalnego znaczenia w kodzieSymbol("some message")
staje się{message:'some message'}
, prawdopodobnie obiekt ma się tu lepiej, ponieważ można dodać wiele pól.Ten post dotyczy
Symbol()
dostarczonych rzeczywistych przykładów, które mogłem znaleźć / stworzyć, oraz faktów i definicji, które mogłem znaleźć.TLDR;
Jest
Symbol()
to typ danych wprowadzony wraz z wydaniem ECMAScript 6 (ES6).Istnieją dwa ciekawe fakty na temat Symbolu.
pierwszy typ danych i jedyny typ danych w JavaScript, który nie ma literału
każda zmienna zdefiniowana za pomocą
Symbol()
otrzymuje unikalną treść, ale nie jest tak naprawdę prywatna .wszelkie dane mają swój własny Symbol, a dla tych samych danych Symbole byłyby takie same . Więcej informacji w następnym akapicie, w przeciwnym razie nie jest to TLRD; :)
Jak zainicjować symbol?
1. Aby uzyskać unikalny identyfikator z wartością do debugowania
Możesz to zrobić w ten sposób:
Lub w ten sposób:
"some text here"
Ciąg nie mogą być pozyskiwane z symbolem, to tylko opis dla celów debugowania. Nie zmienia to w żaden sposób zachowania symbolu. Chociaż możesz toconsole.log
zrobić (co jest sprawiedliwe, ponieważ wartość służy do debugowania, aby nie pomylić tego dziennika z innym wpisem):2. Aby uzyskać symbol dla niektórych danych łańcuchowych
W tym przypadku wartość symbolu jest faktycznie brana pod uwagę i w ten sposób dwa symbole mogą nie być unikalne.
Nazwijmy te symbole symbolami „drugiego rodzaju”. Nie przecinają się z symbolami „pierwszego typu” (tj. Tymi, które są zdefiniowane za pomocą
Symbol(data)
w żaden sposób z ).Następne dwa akapity dotyczą tylko pierwszego typu symbolu.
Jak korzystać z Symbol zamiast starszych typów danych?
Rozważmy najpierw obiekt, standardowy typ danych. Możemy zdefiniować tam kilka par klucz-wartość i uzyskać dostęp do tych wartości, określając klucz.
Co jeśli mamy dwie osoby o imieniu Piotr?
Robiąc to:
nie miałoby sensu.
Wydaje się więc, że jest to problem dwóch absolutnie różnych osób o tym samym nazwisku. Odwołajmy się zatem do nowych
Symbol()
. To jak osoba w prawdziwym życiu - każda osoba jest wyjątkowa , ale jej nazwiska mogą być równe. Zdefiniujmy dwie „osoby”.Teraz mamy dwie różne osoby o tym samym nazwisku. Czy nasze osoby są naprawdę różne? Oni są; możesz to sprawdzić:
Jak na tym skorzystamy?
Możemy dokonać dwóch wpisów w Twoim obiekcie dla różnych osób i nie można ich w żaden sposób pomylić.
Dzięki tej inicjalizacji absolutnie niemożliwe jest pomylenie wpisów dla pierwszej i drugiej osoby. Wołanie
console.log
o nie poprawnie wypisze ich drugie imię.W przypadku użycia w obiekcie, czym różni się od definiowania właściwości niepoliczalnej?
Rzeczywiście istniał już sposób zdefiniowania właściwości, przed którą należy ukryć
Object.keys
i wyliczenia. Oto on:Jaką różnicę
Symbol()
tam przynosi? Różnica polega na tym, że nadal można uzyskać właściwość zdefiniowanąObject.defineProperty
w zwykły sposób:A jeśli zdefiniowano za pomocą Symbolu jak w poprzednim akapicie:
Będziesz mógł otrzymać jego wartość tylko wtedy, gdy znasz jej zmienną, tj
Co więcej, zdefiniowanie innej właściwości pod kluczem
"apple"
spowoduje, że obiekt porzuci starszą (a jeśli zostanie zakodowany na stałe, może wyrzucić błąd). Nie ma już jabłek! Szkoda. Odnosząc się do poprzedniego akapitu, Symbole są unikalne i definiują klucz,Symbol()
który uczyni go unikalnym.Konwersja i sprawdzanie typów
W przeciwieństwie do innych typów danych, nie można przekonwertować na
Symbol()
inny typ danych.Możliwe jest „uczynienie” symbolu opartym na prymitywnym typie danych przez wywołanie
Symbol(data)
.Pod względem sprawdzania typu nic się nie zmienia.
źródło
Oto jak to widzę. Symbole zapewniają „dodatkowy poziom prywatności”, zapobiegając ujawnieniu kluczy / właściwości obiektu za pomocą popularnych metod, takich jak Object.keys () i JSON.stringify ().
Mimo że dany obiekt jako taki, takie właściwości mogą być nadal ujawniane przez odbicie, proxy, Object.getOwnPropertySymbols () itp., Nie ma naturalnych sposobów dostępu do nich za pomocą kilku bezpośrednich metod, które mogą być czasami wystarczające z perspektywy OOP.
źródło
Symbol JS to nowy prymitywny typ danych. Są to tokeny, które służą jako unikalne identyfikatory . Symbol można utworzyć za pomocą
Symbol
konstruktora. Weźmy na przykład ten fragment kodu z MDN:Często przydatne jest używanie symboli jako unikatowych kluczy właściwości obiektu, na przykład:
źródło
Źródło
źródło