Anwendungsfälle: #
-private Felder
Vorwort:
Datenschutz 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 .
class A {
#a: number;
constructor(a: number) {
this.#a = a;
}
}
let foo: A = new A(42);
foo.#a; // error, not allowed outside class bodies
(foo as any).#bar; // still nope.
Sichere Klassenvererbung
#
-private Felder erhalten einen eindeutigen Bereich. Klassenhierarchien können implementiert werden, ohne dass private Eigenschaften mit gleichen Namen versehentlich überschrieben werden.
class A {
#a = "a";
fnA() { return this.#a; }
}
class B extends A {
#a = "b";
fnB() { return this.#a; }
}
const b = new B();
b.fnA(); // returns "a" ; unique property #a in A is still retained
b.fnB(); // returns "b"
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 weggelassen
Integrierte 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 ):
class Foo {
#bar = 42;
baz = "huhu";
}
Object.keys(new Foo()); // [ "baz" ]
Anwendungsfälle: private
Schlüsselwort
Vorwort:
Zugriff 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
/ <>
) und any
typisierter Variablenzuweisung:
class A {
constructor(private a: number) { }
}
const a = new A(10);
a.a; // TS compile error
(a as any).a; // works
const casted: any = a; casted.a // works
TS ermöglicht sogar den dynamischen Eigenschaftszugriff eines private
Mitglieds mit einer Notluke :
class C {
private foo = 10;
}
const res = new C()["foo"]; // 10, res has type number
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ür target
ES2015
/ ES6
oder höher verfügbar . WeakMap
Wird in ES6 + intern als Downlevel-Implementierung verwendet (siehe hier ). Native- #
private Felder sind derzeit erforderlich target
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 ).
- Bisher sind in TS keine harten Methoden für Privatklassen verfügbar.
- Einige Leute mögen die
private
Keyword-Notation besser 😊.
Hinweis zu beiden
Beide Ansätze erzeugen zur Kompilierungszeit eine Art Nominal- oder Markentyp.
class A1 { private a = 0; }
class A2 { private a = 42; }
const a: A1 = new A2();
// error: "separate declarations of a private property 'a'"
// same with hard private fields
Außerdem ermöglichen beide den instanzübergreifenden Zugriff: Eine Klasseninstanz A
kann auf private Mitglieder anderer A
Instanzen zugreifen :
class A {
private a = 0;
method(arg: A) {
console.log(arg.a); // works
}
}
Quellen