Was sind in TypeScript 3.8+ die Unterschiede zwischen der Verwendung des private
Schlüsselworts zum Markieren eines privaten Mitglieds:
class PrivateKeywordClass {
private value = 1;
}
Und unter Verwendung der für JavaScript vorgeschlagenen#
privaten Felder :
class PrivateFieldClass {
#value = 1;
}
Soll ich eins dem anderen vorziehen?
javascript
typescript
class
encapsulation
Matt Bierner
quelle
quelle
Antworten:
Privates Schlüsselwort
Das private Schlüsselwort in TypeScript ist eine Anmerkung zur Kompilierungszeit . Es teilt dem Compiler mit, dass auf eine Eigenschaft nur innerhalb dieser Klasse zugegriffen werden soll:
Die Überprüfung der Kompilierungszeit kann jedoch leicht umgangen werden, indem beispielsweise die Typinformationen weggeworfen werden:
Das
private
Schlüsselwort wird zur Laufzeit auch nicht erzwungenAusgelassenes JavaScript
Beim Kompilieren von TypeScript zu JavaScript wird das
private
Schlüsselwort einfach entfernt:Wird:
Daran können Sie erkennen, warum das
private
Schlüsselwort keinen Laufzeitschutz bietet: Im generierten JavaScript ist es nur eine normale JavaScript-Eigenschaft.Private Felder
Private Felder stellen sicher, dass Eigenschaften zur Laufzeit privat bleiben :
TypeScript gibt auch einen Fehler bei der Kompilierung aus, wenn Sie versuchen, ein privates Feld außerhalb einer Klasse zu verwenden:
Private Felder stammen aus einem JavaScript-Vorschlag und funktionieren auch in normalem JavaScript.
Ausgelassenes JavaScript
Wenn Sie private Felder in TypeScript verwenden und ältere Versionen von JavaScript für Ihre Ausgabe verwenden, z. B.
es6
oderes2018
, versucht TypeScript, Code zu generieren, der das Laufzeitverhalten privater Felder emuliertWenn Sie ein Targeting durchführen
esnext
, gibt TypeScript das private Feld aus:Welches soll ich verwenden?
Es hängt davon ab, was Sie erreichen wollen.
Das
private
Schlüsselwort ist eine gute Standardeinstellung. Es erreicht das, wofür es entwickelt wurde, und wird seit Jahren von TypeScript-Entwicklern erfolgreich eingesetzt. Wenn Sie über eine vorhandene Codebasis verfügen, müssen Sie nicht den gesamten Code wechseln, um private Felder zu verwenden. Dies gilt insbesondere dann, wenn Sie kein Targeting durchführenesnext
, da die von TS für private Felder ausgegebene JS möglicherweise Auswirkungen auf die Leistung hat. Beachten Sie auch, dass private Felder andere subtile, aber wichtige Unterschiede zumprivate
Schlüsselwort aufweisenWenn Sie jedoch die Privatsphäre der Laufzeit erzwingen müssen oder
esnext
JavaScript ausgeben , sollten Sie private Felder verwenden.Denken Sie auch daran, dass sich Organisations- / Community-Konventionen zur Verwendung des einen oder anderen ebenfalls ändern werden, wenn private Felder in den JavaScript / TypeScript-Ökosystemen weiter verbreitet werden
Andere bemerkenswerte Unterschiede
Private Felder werden von
Object.getOwnPropertyNames
und ähnlichen Methoden nicht zurückgegebenPrivate Felder werden von nicht serialisiert
JSON.stringify
Es gibt wichtige Randfälle im Zusammenhang mit der Vererbung.
TypeScript verbietet beispielsweise das Deklarieren einer privaten Eigenschaft in einer Unterklasse mit demselben Namen wie eine private Eigenschaft in der Oberklasse.
Dies gilt nicht für private Felder:
Ein
private
Schlüsselwort private Eigenschaft ohne Initialisierer generiert keine Eigenschaftsdeklaration im ausgegebenen JavaScript:Kompiliert zu:
Während private Felder immer eine Eigenschaftsdeklaration generieren:
Kompiliert zu (beim Zielen
esnext
):Weiterführende Literatur:
quelle
Anwendungsfälle:
#
-private FelderVorwort:
#
-privat, hart privat, Laufzeit privatDatenschutz zur Kompilierungs- und Laufzeit
#
-private Felder bieten Datenschutz zur Kompilierungs- und Laufzeit, der nicht "hackbar" ist. Es ist ein Mechanismus, der den direkten Zugriff auf ein Mitglied von außerhalb des Klassenkörpers verhindert .Sichere Klassenvererbung
#
-private Felder erhalten einen eindeutigen Bereich. Klassenhierarchien können implementiert werden, ohne dass private Eigenschaften mit gleichen Namen versehentlich überschrieben werden.Der TS-Compiler gibt glücklicherweise einen Fehler aus, wenn
private
die Gefahr besteht , dass Eigenschaften überschrieben werden (siehe dieses Beispiel) ). Aufgrund der Art einer Funktion zur Kompilierungszeit ist zur Laufzeit jedoch immer noch alles möglich, da Kompilierungsfehler ignoriert und / oder ausgegebener JS-Code verwendet wird.Externe Bibliotheken
Bibliotheksautoren können
#
private Kennungen umgestalten, ohne dass dies zu einer grundlegenden Änderung für Clients führt. Bibliotheksbenutzer auf der anderen Seite sind vor dem Zugriff auf interne Felder geschützt.In der JS-API werden
#
private Felder weggelassenIntegrierte JS-Funktionen und -Methoden ignorieren
#
-private Felder. Dies kann zur Laufzeit zu einer besser vorhersehbaren Eigenschaftsauswahl führen. Beispiele:Object.keys
,Object.entries
,JSON.stringify
,for..in
Schleife und andere ( Codebeispiel , siehe auch Matt Bierner Antwort ):Anwendungsfälle:
private
SchlüsselwortVorwort:
private
Schlüsselwort in TS-DokumentenZugriff auf interne Klassen-API und -Status (nur Datenschutz zur Kompilierungszeit)
private
Mitglieder einer Klasse sind zur Laufzeit herkömmliche Eigenschaften. Wir können diese Flexibilität nutzen, um von außen auf die klasseninterne API oder den Status zuzugreifen. Um Compilerprüfungen zu erfüllen,@ts-ignore
können unter anderem Mechanismen wie Typzusicherungen, dynamischer Eigenschaftszugriff oder verwendet werden.Beispiel mit Typzusicherung (
as
/<>
) undany
typisierter Variablenzuweisung:TS ermöglicht sogar den dynamischen Eigenschaftszugriff eines
private
Mitglieds mit einer Notluke :Wo kann ein privater Zugang sinnvoll sein? (1) Unit-Tests, (2) Debugging- / Protokollierungssituationen oder (3) andere fortgeschrittene Fallszenarien mit projektinternen Klassen (offene Liste).
Der Zugriff auf interne Variablen ist etwas widersprüchlich - sonst hätten Sie sie gar nicht erst gemacht
private
. Bei Unit-Tests handelt es sich beispielsweise um schwarz / graue Kästchen mit privaten Feldern, die als Implementierungsdetail ausgeblendet sind. In der Praxis kann es jedoch von Fall zu Fall gültige Ansätze geben.Verfügbar in allen ES-Umgebungen
TS-
private
Modifikatoren können mit allen ES-Zielen verwendet werden.#
-private Felder sind nur fürtarget
ES2015
/ES6
oder höher verfügbar .WeakMap
Wird in ES6 + intern als Downlevel-Implementierung verwendet (siehe hier ). Native-#
private Felder sind derzeit erforderlichtarget
esnext
.Konsistenz und Kompatibilität
Teams verwenden möglicherweise Codierungsrichtlinien und Linter-Regeln, um die Verwendung
private
als einzigen Zugriffsmodifikator zu erzwingen . Diese Einschränkung kann zur Konsistenz beitragen und Verwechslungen mit der#
privaten Feldnotation auf abwärtskompatible Weise vermeiden .Bei Bedarf sind Parametereigenschaften (Konstruktorzuweisungskürzel) ein Show-Stopper. Sie können nur mit
private
Schlüsselwörtern verwendet werden, und es gibt noch keine Pläne , sie für#
private Felder zu implementieren .Andere Gründe
private
kann in einigen Down-Leveling-Fällen eine bessere Laufzeitleistung bieten (siehe hier ).private
Keyword-Notation besser 😊.Hinweis zu beiden
Beide Ansätze erzeugen zur Kompilierungszeit eine Art Nominal- oder Markentyp.
Außerdem ermöglichen beide den instanzübergreifenden Zugriff: Eine Klasseninstanz
A
kann auf private Mitglieder andererA
Instanzen zugreifen :Quellen
quelle