Ja, füge dem Namen ein #
als Präfix hinzu und nehme ihn in die Klassendefinition auf, nicht nur in den Konstruktor.
MDN Docs
Echte private Eigenschaften wurden schließlich in ES2022 hinzugefügt. Seit dem 01.01.2023 werden private Eigenschaften (Felder und Methoden) in allen gängigen Browsern seit mindestens einem Jahr unterstützt, aber 5-10% der Benutzer arbeiten immer noch mit älteren Browsern [Can I Use].
Beispiel:
class Person {
#age
constructor(name) {
this.name = name; // dies ist öffentlich
this.#age = 20; // dies ist privat
}
greet() {
// hier können wir sowohl auf Name als auch auf Alter zugreifen
console.log(`Name: ${this.name}, Alter: ${this.#age}`);
}
}
let joe = new Person('Joe');
joe.greet();
// hier können wir auf den Namen, aber nicht auf das Alter zugreifen
Im Folgenden sind Methoden aufgeführt, um Eigenschaften in vor-ES2022-Umgebungen privat zu halten, mit verschiedenen Kompromissen.
Begrenzte Variablen
Der Ansatz hier besteht darin, den Bereich der Konstruktorfunktion, der privat ist, zu verwenden, um private Daten zu speichern. Damit Methoden Zugriff auf diese privaten Daten haben, müssen sie ebenfalls im Konstruktor erstellt werden, was bedeutet, dass sie mit jeder Instanz neu erstellt werden. Dies ist mit einer Leistungseinbuße und erhöhtem Speicherbedarf verbunden, kann aber akzeptabel sein. Die Strafe kann vermieden werden für Methoden, die keinen Zugriff auf private Daten benötigen, indem sie auf herkömmliche Weise deklariert werden.
Beispiel:
class Person {
constructor(name) {
let age = 20; // dies ist privat
this.name = name; // dies ist öffentlich
this.greet = () => {
// hier können wir sowohl auf Name als auch auf Alter zugreifen
console.log(`Name: ${this.name}, Alter: ${age}`);
};
}
anotherMethod() {
// hier können wir auf den Namen, aber nicht auf das Alter zugreifen
}
}
let joe = new Person('Joe');
joe.greet();
// hier können wir auf den Namen, aber nicht auf das Alter zugreifen
Begrenzte WeakMap
Ein WeakMap kann verwendet werden, um die Leistung des obigen Ansatzes zu verbessern, jedoch auf Kosten von noch mehr Unordnung. WeakMaps verknüpfen Daten mit Objekten (hier, Klasseninstanzen) so, dass sie nur mit dieser WeakMap darauf zugreifen können. Daher verwenden wir die Methode der begrenzten Variablen zur Erstellung einer privaten WeakMap und verwenden dann diese WeakMap, um private Daten, die mit this
verknüpft sind, abzurufen. Dies ist schneller als die Methode mit begrenzten Variablen, da alle Instanzen eine einzige WeakMap gemeinsam nutzen können und somit Methoden nicht neu erstellt werden müssen, um auf ihre eigenen WeakMaps zugreifen zu können.
Beispiel:
let Person = (function () {
let privateProps = new WeakMap();
return class Person {
constructor(name) {
this.name = name; // dies ist öffentlich
privateProps.set(this, {age: 20}); // dies ist privat
}
greet() {
// Hier können wir sowohl auf Name als auch auf Alter zugreifen
console.log(`Name: ${this.name}, Alter: ${privateProps.get(this).age}`);
}
};
})();
let joe = new Person('Joe');
joe.greet();
// hier können wir auf den Namen, aber nicht auf das Alter zugreifen
Bei diesem Beispiel wird eine WeakMap mit Objektschlüsseln verwendet, um eine WeakMap für mehrere private Eigenschaften zu verwenden. Sie könnten auch mehrere WeakMaps verwenden und sie auf die gleiche Weise wie privateAge.set(this, 20)
verwenden oder einen kleinen Wrapper schreiben und ihn auf andere Weise verwenden, z. B. privateProps.set(this, 'age', 0)
.
Die Datenschutzmaßnahmen dieses Ansatzes könnten theoretisch durch Manipulation des globalen WeakMap
-Objekts umgangen werden. Gesagt sei jedoch, dass das gesamte JavaScript durch veränderte Globale gefährdet ist.
(Dieser Ansatz könnte auch mit Map
durchgeführt werden, aber WeakMap
ist besser, da Map
Speicherlecks verursacht, es sei denn, man ist sehr vorsichtig, und für diesen Zweck sind die beiden ansonsten nicht unterschiedlich.)
Halb-Antwort: Begrenzte Symbole
Ein Symbol ist ein Typ von primitivem Wert, der als Eigenschaftsname anstelle eines Strings dienen kann. Sie können die Methode der begrenzten Variablen verwenden, um ein privates Symbol zu erstellen und dann private Daten unter this[mySymbol]
zu speichern.
Die Datenschutzmaßnahmen dieses Ansatzes können mit Object.getOwnPropertySymbols
umgangen werden, sind jedoch etwas umständlich.
Beispiel:
let Person = (() => {
let ageKey = Symbol();
return class Person {
constructor(name) {
this.name = name; // dies ist öffentlich
this[ageKey] = 20; // dies soll privat sein
}
greet() {
// Hier können wir sowohl auf Name als auch auf Alter zugreifen
console.log(`Name: ${this.name}, Alter: ${this[ageKey]}`);
}
}
})();
let joe = new Person('Joe');
joe.greet();
// Hier können wir auf Joe's Namen und, mit etwas Mühe, auf sein Alter zugreifen. Wir können
// nicht direkt auf ageKey zugreifen, aber wir können ihn erhalten, indem wir alle Symbol-Eigenschaften
// auf `joe` mit `Object.getOwnPropertySymbols(joe)` auflisten.
Beachten Sie, dass das Festlegen einer Eigenschaft als nicht aufzählbar mit Object.defineProperty
nicht verhindert, dass sie in Object.getOwnPropertySymbols
enthalten ist.
Halbabtörn: Unterstriche
Die alte Konvention besteht einfach darin, eine öffentliche Eigenschaft mit einem Unterstrichpräfix zu verwenden. Dies hält sie nicht privat, vermittelt jedoch gut an die Leser, dass sie als privat behandelt werden sollten, was oft ausreicht. Im Gegenzug erhalten wir einen Ansatz, der leichter lesbar, leichter zu tippen und schneller als die anderen Workarounds ist.
Beispiel:
class Person {
constructor(name) {
this.name = name; // dies ist öffentlich
this._age = 20; // dies soll privat sein
}
greet() {
// Hier können wir sowohl auf Name als auch auf Alter zugreifen
console.log(`Name: ${this.name}, Alter: ${this._age}`);
}
}
let joe = new Person('Joe');
joe.greet();
// Hier können wir sowohl auf Joe's Namen als auch auf sein Alter zugreifen. Aber wir wissen, dass wir nicht auf sein Alter zugreifen sollen, was uns möglicherweise stoppt.
Zusammenfassung
- ES2022: großartig, aber noch nicht von allen Besuchern unterstützt
- Begrenzte Variablen: privat, langsamer, umständlich
- Begrenzte WeakMaps: hackbar, umständlich
- Begrenzte Symbole: aufzählbar und hackbar, etwas umständlich
- Unterstriche: nur eine Anfrage nach Datenschutz, keine anderen Nachteile