Pour développer la réponse de @ loganfsmyth:
Les seules données vraiment privées en JavaScript sont toujours des variables de portée. Vous ne pouvez pas avoir de propriétés privées au sens de propriétés accessibles en interne de la même manière que les propriétés publiques, mais vous pouvez utiliser des variables de portée pour stocker des données privées.
Variables de portée
L'approche ici consiste à utiliser la portée de la fonction constructeur, qui est privée, pour stocker des données privées. Pour que les méthodes aient accès à ces données privées, elles doivent également être créées dans le constructeur, ce qui signifie que vous les recréez avec chaque instance. Il s'agit d'une pénalité liée aux performances et à la mémoire, mais certains pensent que la pénalité est acceptable. La pénalité peut être évitée pour les méthodes qui n'ont pas besoin d'accéder aux données privées en les ajoutant au prototype comme d'habitude.
Exemple:
function Person(name) {
let age = 20; // this is private
this.name = name; // this is public
this.greet = function () {
// here we can access both name and age
console.log(`name: ${this.name}, age: ${age}`);
};
}
let joe = new Person('Joe');
joe.greet();
// here we can access name but not age
Scope WeakMap
Un WeakMap peut être utilisé pour éviter les performances et la pénalité de mémoire de l'approche précédente. Les WeakMaps associent les données aux objets (ici, les instances) de manière à ce qu'elles ne soient accessibles qu'en utilisant ce WeakMap. Ainsi, nous utilisons la méthode des variables de portée pour créer un WeakMap privé, puis utilisons ce WeakMap pour récupérer les données privées associées à this
. C'est plus rapide que la méthode des variables de portée car toutes vos instances peuvent partager une seule WeakMap, vous n'avez donc pas besoin de recréer des méthodes juste pour leur faire accéder à leurs propres WeakMaps.
Exemple:
let Person = (function () {
let privateProps = new WeakMap();
class Person {
constructor(name) {
this.name = name; // this is public
privateProps.set(this, {age: 20}); // this is private
}
greet() {
// Here we can access both name and age
console.log(`name: ${this.name}, age: ${privateProps.get(this).age}`);
}
}
return Person;
})();
let joe = new Person('Joe');
joe.greet();
// here we can access joe's name but not age
Cet exemple utilise un objet pour utiliser un WeakMap pour plusieurs propriétés privées; vous pouvez également utiliser plusieurs WeakMaps et les utiliser comme age.set(this, 20)
, ou écrire un petit wrapper et l'utiliser d'une autre manière, comme privateProps.set(this, 'age', 0)
.
La confidentialité de cette approche pourrait théoriquement être violée en altérant l' WeakMap
objet global . Cela dit, tout JavaScript peut être brisé par des globaux mutilés. Notre code est déjà construit sur l'hypothèse que cela ne se produit pas.
(Cette méthode pourrait également être utilisée avec Map
, mais elle WeakMap
est meilleure car Map
elle créera des fuites de mémoire à moins que vous ne soyez très prudent, et à cette fin, les deux ne sont pas autrement différents.)
Demi-réponse: symboles de portée
Un symbole est un type de valeur primitive qui peut servir de nom de propriété. Vous pouvez utiliser la méthode des variables de portée pour créer un symbole privé, puis stocker des données privées sur this[mySymbol]
.
La confidentialité de cette méthode peut être violée à l'aide Object.getOwnPropertySymbols
, mais est quelque peu difficile à faire.
Exemple:
let Person = (function () {
let ageKey = Symbol();
class Person {
constructor(name) {
this.name = name; // this is public
this[ageKey] = 20; // this is intended to be private
}
greet() {
// Here we can access both name and age
console.log(`name: ${this.name}, age: ${this[ageKey]}`);
}
}
return Person;
})();
let joe = new Person('Joe');
joe.greet();
// Here we can access joe's name and, with a little effort, age. ageKey is
// not in scope, but we can obtain it by listing all Symbol properties on
// joe with `Object.getOwnPropertySymbols(joe)`.
Demi-réponse: Souligne
L'ancien défaut, utilisez simplement une propriété publique avec un préfixe de soulignement. Bien qu'elle ne soit en aucun cas une propriété privée, cette convention est suffisamment répandue pour faire un bon travail en communiquant que les lecteurs doivent traiter la propriété comme privée, ce qui fait souvent le travail. En échange de ce laps de temps, nous obtenons une approche plus facile à lire, plus facile à taper et plus rapide.
Exemple:
class Person {
constructor(name) {
this.name = name; // this is public
this._age = 20; // this is intended to be private
}
greet() {
// Here we can access both name and age
console.log(`name: ${this.name}, age: ${this._age}`);
}
}
let joe = new Person('Joe');
joe.greet();
// Here we can access both joe's name and age. But we know we aren't
// supposed to access his age, which just might stop us.
Conclusion
Depuis ES2017, il n'y a toujours pas de moyen idéal pour faire des propriétés privées. Diverses approches ont des avantages et des inconvénients. Les variables de portée sont vraiment privées; les WeakMaps de portée sont très privés et plus pratiques que les variables de portée; les symboles de portée sont raisonnablement privés et raisonnablement pratiques; les soulignés sont souvent assez privés et très pratiques.