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 privatedie 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..inSchleife und andere ( Codebeispiel , siehe auch Matt Bierner Antwort ):
class Foo {
#bar = 42;
baz = "huhu";
}
Object.keys(new Foo()); // [ "baz" ]
Anwendungsfälle: privateSchlüsselwort
Vorwort:
Zugriff auf interne Klassen-API und -Status (nur Datenschutz zur Kompilierungszeit)
privateMitglieder 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-ignorekönnen unter anderem Mechanismen wie Typzusicherungen, dynamischer Eigenschaftszugriff oder verwendet werden.
Beispiel mit Typzusicherung ( as/ <>) und anytypisierter 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 privateMitglieds 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- privateModifikatoren können mit allen ES-Zielen verwendet werden. #-private Felder sind nur für target ES2015/ ES6oder höher verfügbar . WeakMapWird 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 privateals 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 privateSchlüsselwörtern verwendet werden, und es gibt noch keine Pläne , sie für #private Felder zu implementieren .
Andere Gründe
privatekann 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
privateKeyword-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 Akann auf private Mitglieder anderer AInstanzen zugreifen :
class A {
private a = 0;
method(arg: A) {
console.log(arg.a); // works
}
}
Quellen