W TypeScript 3.8+ jakie są różnice między użyciem private
słowa kluczowego do oznaczenia członka jako prywatny:
class PrivateKeywordClass {
private value = 1;
}
I używając #
prywatnych pól proponowanych dla JavaScript :
class PrivateFieldClass {
#value = 1;
}
Czy powinienem preferować jeden od drugiego?
javascript
typescript
class
encapsulation
Matt Bierner
źródło
źródło
Odpowiedzi:
Prywatne słowo kluczowe
Prywatny kluczowe w maszynopisie jest czas kompilacji adnotacji. Informuje kompilator, że właściwość powinna być dostępna tylko wewnątrz tej klasy:
Sprawdzanie czasu kompilacji można jednak łatwo ominąć, na przykład odrzucając informacje o typie:
Słowo
private
kluczowe nie jest również wymuszane w czasie wykonywaniaEmitowany JavaScript
Podczas kompilowania TypeScript do JavaScript
private
słowo kluczowe jest po prostu usuwane:Staje się:
Na podstawie tego możesz zobaczyć, dlaczego
private
słowo kluczowe nie zapewnia żadnej ochrony środowiska wykonawczego: w wygenerowanym JavaScript jest to zwykła właściwość JavaScript.Pola prywatne
Pola prywatne zapewniają, że właściwości są prywatne w czasie wykonywania :
TypeScript wyświetli również błąd czasu kompilacji, jeśli spróbujesz użyć prywatnego pola poza klasą:
Pola prywatne pochodzą z propozycji JavaScript, a także działają w normalnym JavaScript.
Emitowany JavaScript
Jeśli używasz pól prywatnych w TypeScript i celujesz w starsze wersje JavaScript dla swoich danych wyjściowych, takich jak
es6
lubes2018
, TypeScript spróbuje wygenerować kod, który emuluje zachowanie w czasie wykonywania pól prywatnychJeśli
esnext
celujesz, TypeScript wyśle prywatne pole:Którego powinienem użyć?
To zależy od tego, co próbujesz osiągnąć.
Słowo
private
kluczowe jest w porządku. Osiąga to, do czego został zaprojektowany i od lat jest z powodzeniem wykorzystywany przez programistów TypeScript. A jeśli masz już bazę kodu, nie musisz przełączać całego kodu, aby korzystać z pól prywatnych. Jest to szczególnie prawdziwe, jeśli nie jesteś celemesnext
, ponieważ JS emitowany przez TS dla pól prywatnych może mieć wpływ na wydajność. Należy również pamiętać, że pola prywatne mają inne subtelne, ale ważne różnice odprivate
słowa kluczowegoJeśli jednak chcesz wymusić prywatność środowiska wykonawczego lub wyprowadzasz
esnext
JavaScript, powinieneś użyć pól prywatnych.Należy również pamiętać, że konwencje organizacji / społeczności dotyczące korzystania z jednego lub drugiego będą również ewoluować, gdy prywatne pola staną się bardziej rozpowszechnione w ekosystemach JavaScript / TypeScript
Inne różnice uwagi
Pola prywatne nie są zwracane za pomocą
Object.getOwnPropertyNames
podobnych metodPola prywatne nie są serializowane przez
JSON.stringify
Istnieją ważne przypadki brzegowe wokół dziedziczenia.
Na przykład TypeScript zabrania deklarowania własności prywatnej w podklasie o takiej samej nazwie jak własność prywatna w nadklasie.
Nie dotyczy to pól prywatnych:
Słowo
private
kluczowe własność prywatna bez inicjatora nie wygeneruje deklaracji właściwości w emitowanym JavaScript:Kompiluje do:
Podczas gdy pola prywatne zawsze generują deklarację właściwości:
Kompiluje do (podczas targetowania
esnext
):Dalsza lektura:
źródło
Przypadki użycia:
#
-prywatne polaPrzedmowa:
#
synonimowe : -prywatne, trudne prywatne, prywatne w czasie wykonywaniaPrywatność w czasie kompilacji i wykonywania
#
Pola prywatna zapewnić kompilacji i prywatność run-time, która nie jest „hackable”. Jest to mechanizm, aby uniemożliwić dostęp do członka z zewnątrz ciała klasy w żaden bezpośredni sposób .Bezpieczne dziedziczenie klas
#
-prywatne pola mają unikalny zasięg. Hierarchie klas mogą być implementowane bez przypadkowego nadpisywania własności prywatnych o takich samych nazwach.Na szczęście kompilator TS emituje błąd, gdy
private
istnieje ryzyko , że właściwości zostaną zastąpione (patrz ten przykład ). Ale ze względu na naturę funkcji czasu kompilacji wszystko jest nadal możliwe w czasie wykonywania, biorąc pod uwagę błędy kompilacji są ignorowane i / lub wykorzystywany jest kod JS.Biblioteki zewnętrzne
Autorzy bibliotek mogą refaktoryzować
#
-prywatne identyfikatory bez powodowania przełomowej zmiany dla klientów. Użytkownicy biblioteki z drugiej strony są chronieni przed dostępem do pól wewnętrznych.Interfejs API JS pomija
#
pola -prywatneWbudowane funkcje i metody JS ignorują
#
pola -prywatne. Może to skutkować bardziej przewidywalnym wyborem właściwości w czasie wykonywania. Przykłady:Object.keys
,Object.entries
,JSON.stringify
,for..in
pętla i inni ( przykładowy kod ; patrz także Matt Bierner za odpowiedź ):Przypadki użycia:
private
słowo kluczowePrzedmowa:
private
słowo kluczowe w dokumentach TSDostęp do interfejsu API klasy wewnętrznej i stanu (prywatność tylko podczas kompilacji)
private
członkowie klasy są właściwościami konwencjonalnymi w czasie wykonywania. Możemy wykorzystać tę elastyczność, aby uzyskać dostęp do wewnętrznego interfejsu API klasy lub stanu z zewnątrz. Aby spełnić wymagania kompilatora, mechanizmy takie jak asercje typu, dynamiczny dostęp do właściwości lub@ts-ignore
mogą być używane między innymi.Przykład z asercją typu (
as
/<>
) iany
przypisaniem zmiennej typu:TS pozwala nawet na dynamiczny dostęp do właściwości
private
elementu z klapą ewakuacyjną :Gdzie prywatny dostęp może mieć sens? (1) testy jednostkowe, (2) sytuacje debugowania / rejestrowania lub (3) inne zaawansowane scenariusze przypadków z klasami wewnętrznymi projektu (lista otwarta).
Dostęp do zmiennych wewnętrznych jest trochę sprzeczny - inaczej nie stworzyłbyś ich
private
w pierwszej kolejności. Na przykład testy jednostkowe powinny być czarnymi / szarymi skrzynkami z prywatnymi polami ukrytymi jako szczegóły implementacji. W praktyce jednak mogą istnieć odpowiednie podejścia w poszczególnych przypadkach.Dostępne we wszystkich środowiskach ES
private
Modyfikatory TS można stosować ze wszystkimi celami ES.#
-prywatne pola są dostępne tylko dlatarget
ES2015
/ES6
lub wyższej. W ES6 +WeakMap
jest wykorzystywany wewnętrznie jako implementacja niższego poziomu (patrz tutaj ). Natywne#
pola prywatne obecnie wymagajątarget
esnext
.Spójność i kompatybilność
Zespoły mogą korzystać ze wskazówek dotyczących kodowania i reguł linijek, aby wymusić użycie
private
jako jedynego modyfikatora dostępu. To ograniczenie może pomóc zachować spójność i uniknąć pomylenia z#
notacją pola -prywatnego w sposób zgodny z poprzednimi wersjami.W razie potrzeby właściwości parametru (skrót konstruktora) są ogranicznikiem pokazu. Można ich używać tylko ze
private
słowem kluczowym i nie ma jeszcze planów ich wdrożenia dla#
pól -prywatnych.Inne powody
private
może zapewnić lepszą wydajność w czasie wykonywania w niektórych przypadkach obniżania poziomu (patrz tutaj ).private
notacja słowa kluczowego 😊.Uwaga na oba
Oba podejścia tworzą rodzaj nominalnego lub markowego typu w czasie kompilacji.
Oba umożliwiają także dostęp między instancjami: instancja klasy
A
może uzyskać dostęp do prywatnych członków innychA
instancji:Źródła
źródło