[ Web Proxy ]
URL:
Viewing: https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Classes/Private_elements [Back]  [Original]

Proprits prives - JavaScript | MDN

Cette page a t traduite partir de l'anglais par la communaut. Vous pouvez contribuer en rejoignant la communaut francophone sur MDN Web Docs.

View in English Always switch to English

Proprits prives

Baseline Large disponibilit

Cette fonctionnalit est bien tablie et fonctionne sur de nombreux appareils et versions de navigateurs. Elle est disponible sur tous les navigateurs depuis juillet 2021.

Les proprits prives sont les quivalents des proprits de classe normales, qui sont publiques, comme les champs de classe, les mthodes de classe, etc. Les proprits prives sont cres en utilisant un croisillon # comme prfixe et ne peuvent pas tre rfrence lgalement en dehors de la classe. L'encapsulation de cette isolation dans la classe est gre par le moteur JavaScript.

Les proprits prives n'taient pas disponibles de faon native en JavaScript avant l'apparition de cette syntaxe. En utilisant l'hritage prototypal, ce comportement pouvait tre mul avec des objets WeakMap, ou des fermetures (closures), mais cela n'tait pas aussi pratique que la syntaxe avec #.

Dans cet article

Syntaxe

js
class ClasseAvecProprietesPrivees {
  #champPrive;
  #champPriveAvecInitialisateur = 42;

  #methodePrivee() {
    // 
  }

  static #champPriveStatique;
  static #champPriveStatiqueAvecInitialisateur = 42;

  static #methodePriveeStatique() {
    // 
  }
}

Des restrictions complmentaires s'appliquent :

  • Tous les identifiants privs dclars au sein d'une classe doivent tre uniques. L'espace de noms est partag entre les proprits statiques et celles des instances. La seule exception cette rgle est la dfinition d'une paire d'accesseur/mutateur (getter/setter).
  • Un identifiant priv ne peut pas tre #constructor.

Description

Pour chaque type de proprit d'une classe, on a des quivalents privs :

  • Champs privs
  • Mthodes prives
  • Champs statiques privs
  • Mthodes statiques prives
  • Accesseurs privs
  • Mutateurs privs
  • Accesseurs privs statiques
  • Mutateurs privs statiques

Toutes ces fonctionnalits reprsentent des proprits prives. Toutefois, les constructeurs ne peuvent pas tre privs en JavaScript. Pour empcher une classe d'tre construite en dehors d'elle-mme, il faudra utiliser un marqueur priv.

Les proprits prives sont dclares avec des identifiants prfixs par # (en anglais, on parle de hash names). Le prfixe avec le croisillon fait partie inhrente du nom de la proprit (on peut y voir une analogie avec l'ancienne convention utilisant un tiret bas comme prfixe _champPrive, mais il ne s'agit pas d'une proprit dont le nom est une chane de caractre classique et on ne peut donc pas y accder dynamiquement en utilisant la notation avec les crochets).

Les cas suivants sont des erreurs de syntaxe :

  • Faire rfrence aux noms privs en dehors de la classe.
  • Faire rfrence des proprits prives qui n'ont pas t dclares dans le corps de la classe
  • Tenter de supprimer une proprit prive avec delete.
js
class ClasseAvecChampPrive {
  #champPrive;

  constructor() {;
    delete this.#champPrive; // Erreur de syntaxe
    this.#champNonDeclare = 42; // Erreur de syntaxe
  }
}

const instance = new ClasseAvecChampPrive();
instance.#champPrive; // Erreur de syntaxe

JavaScript est un langage dynamique et peut faire cette vrification la compilation grce la syntaxe particulire des proprits prives.

Note : Le code excut dans la console Google Chrome permet d'accder aux proprits prives en dehors de la classe. Il s'agit d'une drogation propre aux outils de dveloppement.

Si vous tentez d'accder une proprit prive sur un objet qui ne dispose pas de la proprit, vous obtiendrez une exception TypeError et non undefined, comme c'est le cas pour les proprits normales (publiques).

js
class C {
  #x;

  static getX(obj) {
    return obj.#x;
  }
}

console.log(C.getX(new C())); // undefined
console.log(C.getX({})); // TypeError: Cannot read private member #x from an object whose class did not declare it

Cet exemple illustre galement l'accs aux proprits prives depuis les fonctions statiques et pour les instances de la classe dfinies par ailleurs.

L'oprateur in peut tre utilis pour vrifier si un objet tiers possde une proprit prive. L'oprateur renverra true si le champ priv existe, false sinon.

js
class C {
  #x;
  constructor(x) {
    this.#x = x;
  }
  static getX(obj) {
    if (#x in obj) return obj.#x;

    return "obj doit tre une instance de C";
  }
}
console.log(C.getX(new C("toto"))); // "toto"
console.log(C.getX(new C(0.196))); // 0.196
console.log(C.getX(new C(new Date()))); // la date/heure courante
console.log(C.getX({})); // "obj doit tre une instance de C"

Un corollaire cette dclaration pralable et cette absence de suppression est que si on trouve un objet possdant au moins une proprit prive de la classe courante (via un try...catch ou une vrification in), cet objet en possdera toutes les autres proprits prives. Un objet possdant une proprit prive d'une classe signifie gnralement qu'il a t construit par cette classe (a n'est pas forcment le cas).

Les proprits prives ne font par partie du modle d'hritage prototypal, car elles ne sont accessibles qu'au sein du corps de la classe courante et ne sont pas hrites par les sous-classes. Les proprits prives qui ont le mme nom, mais des classes diffrentes sont totalement diffrentes et n'ont aucune relation entre elles. Il faut voir les proprits prives comme des mtadonnes externes rattaches chaque instance, gres par la classe. Pour cette raison, Object.freeze() et Object.seal() n'ont pas d'effet sur les proprits prives.

Pour plus d'informations sur la faon dont les champs privs sont initialiss, voir la page sur les champs publics des classes.

Exemples

Champs privs

Les champs privs regroupent les champs privs des instances et les champs privs statiques. Ils ne sont accessibles qu'au sein de la dclaration de la classe.

Champs privs des instances

l'instar de leurs homologues publics, les champs privs des instances :

  • Sont ajouts avant que le constructeur s'excute pour une classe de base, ou immdiatement aprs l'appel super() pour une sous-classe
  • Uniquement disponible pour les instances de la classe.
js
class ClasseAvecChampPrive {
  #champPrive;

  constructor() {
    this.#champPrive = 42;
  }
}

class SousClasse extends ClasseAvecChampPrive {
  #champPriveSousClasse;

  constructor() {
    super();
    this.#champPriveSousClasse = 23;
  }
}

new SousClasse(); // Dans certains outils de dveloppement, cela affichera SousClasse {#champPrive: 42, #champPriveSousClasse: 23}

Note : La proprit #champPrive, provenant de la classe de base ClasseAvecChampPrive est prive et est donc uniquement accessible l'intrieur de ClasseAvecChampPrive et est inaccessible depuis SousClasse.

Renvoyer un objet diffrent

Le constructeur d'une classe peut renvoyer un objet diffrent, qui sera alors utilis comme nouveau this pour le constructeur de la classe drive. La classe drive pourra alors dfinir des champs privs sur l'objet qui a t renvoy, permettant ainsi indirectement d'adjoindre des champs privs pour des objets qui ne sont pas des instances.

js
class Stamper extends class {
  // Une classe de base dont le constructeur renvoie
  // l'objet qui lui est fourni.
  constructor(obj) {
    return obj;
  }
} {
  // Cette dclaration rajoutera le champ priv
  // sur l'objet renvoy par le constructeur
  // de la classe de base
  #stamp = 42;
  static getStamp(obj) {
    return obj.#stamp;
  }
}

const obj = {};
new Stamper(obj);
// `Stamper` appelle `Base`, qui renvoie `obj`, et `obj` est
// dsormais la valeur `this`. `Stamper` dfinit alors
// `#stamp` sur `obj`

console.log(obj); // Dans certains outils de dveloppement, on verra {#stamp: 42}
console.log(Stamper.getStamp(obj)); // 42
console.log(obj instanceof Stamper); // false

// On ne peut pas ajouter ainsi deux fois des proprits prives
new Stamper(obj); // Error: Initializing an object twice is an error with private fields

Attention : Implmenter un tel fonctionnement sera source de confusion. Il est gnralement recommand de ne rien renvoyer partir du constructeur, a fortiori, quelque chose qui n'a pas de lien avec this.

Champs statiques privs

l'instar de leurs homologues publics, les champs statiques privs :

  • Sont ajouts au constructeur de la classe au moment de l'valuation de la classe
  • Uniquement disponibles sur la classe elle-mme (et non sur les instances)
js
class ClasseAvecChampStatiquePrive {
  static #champStatiquePrive = 42;

  static methodeStatiquePublique() {
    return ClasseAvecChampStatiquePrive.#champStatiquePrive;
  }
}

console.log(ClasseAvecChampStatiquePrive.methodeStatiquePublique()); // 42

Pour les champs statiques privs, seule la classe qui dfinit le champ statique priv peut accder au champ. Cela peut donner des comportements inattendus lorsque this est utilis. Dans l'exemple suivant, this fait rfrence la classe SousClasse (et non la classe ClasseAvecChampStatiquePrive), et quand on essaie d'appeler SousClasse.methodeStatiquePublique(), cela dclenche une erreur TypeError.

js
class ClasseAvecChampStatiquePrive {
  static #champStatiquePrive = 42;

  static methodeStatiquePublique() {
    return this.#champStatiquePrive;
  }
}

class SousClasse extends ClasseAvecChampStatiquePrive {}

SousClasse.methodeStatiquePublique(); // TypeError: Cannot read private member #champStatiquePrive from an object whose class did not declare it

Le mme comportement se produira si la mthode est appele avec super, car les mthodes appeles avec super ne reoivent pas la classe parente comme valeur pour this.

js
class ClasseAvecChampStatiquePrive {
  static #champStatiquePrive = 42;

  static methodeStatiquePublique() {
    // Mme appele avec super, `this` fera rfrence
    //  SousClasse
    return this.#champStatiquePrive;
  }
}

class SousClasse extends ClasseAvecChampStatiquePrive {
  static appelleSuperMethode() {
    return super.methodeStatiquePublique();
  }
}

SousClasse.appelleSuperMethode(); // TypeError: Cannot read private member #champStatiquePrive from an object whose class did not declare it

Une bonne pratique consiste toujours accder aux champs privs statiques avec le nom de la classe plutt qu'avec this, afin que l'hritage ne casse pas la mthode.

Mthodes prives

Les mthodes prives incluent les mthodes prives des instances et les mthodes statiques prives. Les mthodes prives sont uniquement accessibles l'intrieur de la dclaration de la classe.

Mthodes prives des instances

la diffrence de leurs homologues publiques, les mthodes prives des instances :

  • Sont installes immdiatement avant que les champs des instances soient installs
  • Sont uniquement disponibles pour les instances de la classe, et pas sur sa proprit .prototype
js
class ClasseAvecMethodePrivee {
  #methodePrivee() {
    return 42;
  }

  methodePublique() {
    return this.#methodePrivee();
  }
}

const instance = new ClasseAvecMethodePrivee();
console.log(instance.methodePublique()); // 42

Les mthodes prives des instances peuvent tre des gnrateurs, des mthodes asynchrones, des fonctions de gnration asynchrone. Il est aussi possible de crer des accesseurs et mutateurs privs en suivant les mmes rgles de syntaxe que leurs homologues publiques (accesseur et mutateur).

js
class ClasseAvecAccesseurPrive {
  #message;

  get #messageDecore() {
    return `${this.#message}`;
  }
  set #messageDecore(msg) {
    this.#message = msg;
  }

  constructor() {
    this.#messageDecore = "Coucou le monde";
    console.log(this.#messageDecore);
  }
}

new ClasseAvecAccesseurPrive(); // Coucou le monde

la diffrence des mthodes publiques, les mthodes prives ne sont pas accessibles sur la proprit .prototype de leur classe.

js
class C {
  #methode() {}

  static getMethode(x) {
    return x.#methode;
  }
}

console.log(C.getMethode(new C())); // [Function: #methode]
console.log(C.getMethode(C.prototype)); // TypeError: Receiver must be an instance of class C

Mthodes prives statiques

Comme leurs homologues publiques, les mthodes prives statiques :

  • Sont ajoutes au constructeur de la classe au moment de l'valuation de la classe
  • Sont uniquement disponibles sur la classe elle-mme (et non sur les instances).
js
class ClasseAvecMethodePriveeStatique {
  static #methodePriveeStatique() {
    return 42;
  }

  static methodeStatiquePublique() {
    return ClasseAvecMethodePriveeStatique.#methodePriveeStatique();
  }
}

console.log(ClasseAvecMethodePriveeStatique.methodeStatiquePublique()); // 42

Les mthodes prives statiques peuvent tre des gnrateurs, des fonctions asynchrones, ou des gnrateurs asynchrones.

La mme restriction voque pour les champs statiques privs s'applique et peut mener des comportements inattendus lorsqu'on utilise this. Dans l'exemple suivant, quand on essaie d'appeler SousClasse.methodeStatiquePublique(), this fait rfrence la classe SousClasse (et non la classe ClasseAvecMethodePriveeStatique), ce qui entrane une exception TypeError.

js
class ClasseAvecMethodePriveeStatique {
  static #methodePriveeStatique() {
    return 42;
  }

  static methodeStatiquePublique() {
    return this.#methodePriveeStatique();
  }
}

class SousClasse extends ClasseAvecMethodePriveeStatique {}

console.log(SousClasse.methodeStatiquePublique()); // TypeError: Cannot read private member #methodePriveeStatique from an object whose class did not declare it

Simuler des constructeurs privs

Dans d'autres langages, il est possible d'indiquer un constructeur comme priv, ce qui empche d'instancier la classe en dehors d'elle-mme. Seules des mthodes statiques de construction peuvent tre utilises pour crer des instances, voire il n'est pas possible de crer des instances. JavaScript ne dispose pas d'une syntaxe native pour ce faire, mais on peut y parvenir en utilisant un marqueur statique priv.

js
class ConstructeurPrive {
  static #estUneConstructionInterne = false;

  constructor() {
    if (!ConstructeurPrive.#estUneConstructionInterne) {
      throw new TypeError("ConstructeurPrive n'est pas constructible");
    }
    ConstructeurPrive.#estUneConstructionInterne = false;
    // La suite de la logique d'initialisation
  }

  static create() {
    ConstructeurPrive.#estUneConstructionInterne = true;
    const instance = new ConstructeurPrive();
    return instance;
  }
}

new ConstructeurPrive(); // TypeError: ConstructeurPrive n'est pas constructible
ConstructeurPrive.create(); // ConstructeurPrive {}

Spcifications

Spcification
ECMAScript 2027 LanguageSpecification
# prod-PrivateIdentifier

Compatibilit des navigateurs

javascript.classes.private_class_fields

javascript.classes.private_class_fields_in

javascript.classes.private_class_methods

Voir aussi


Web Proxy Viewer  |  New URL  |  Original Page