Site icon Blog ARC Optimizer

Nouveaux champs de classe privée de JavaScript et comment les utiliser –


ES6 a introduit des classes dans JavaScript, mais elles peuvent être trop simplistes pour des applications complexes. Les champs de classe (également appelés propriétés de classe ) visent à fournir des constructeurs plus simples avec des membres privés et statiques. La proposition est actuellement un TC39 étape 3: candidat et devrait être ajoutée à ES2019 (ES10). Les champs privés sont actuellement pris en charge dans Node.js 12, Chrome 74 et Babel.

Un récapitulatif rapide des classes ES6 est utile avant d'examiner comment les champs de classe sont mis en œuvre.

Principes de base des classes ES6

Objet JavaScript- Le modèle d'héritage orienté peut confondre les développeurs provenant de langages tels que C ++, C #, Java et PHP. Pour cette raison, ES6 a introduit les classes . Ils sont principalement du sucre syntaxique mais offrent des concepts de programmation orientée objet plus familiers.

Une classe est un modèle d'objet qui définit le comportement des objets de ce type. La classe Animal suivante définit les animaux génériques (les classes sont normalement désignées par une majuscule initiale pour les distinguer des objets et d'autres types):

 class Animal {

  constructeur (nom = 'anonyme', jambes = 4, bruit = 'rien') {

    this.type = 'animal';
    this.name = nom;
    this.legs = jambes;
    this.noise = bruit;

  }

  parler() {
    console.log (`$ {this.name} dit" $ {this.noise} "`);
  }

  marcher() {
    console.log (`$ {this.name} marche sur $ {this.legs} jambes`);
  }

}

Les déclarations de classe s'exécutent toujours en mode strict. Il n'est pas nécessaire d'ajouter 'use strict' .

La méthode constructeur est exécutée lorsqu'un objet du type Animal est créé. Il définit généralement les propriétés initiales et gère les autres initialisations. speak () et walk () sont des méthodes d'instance qui ajoutent des fonctionnalités supplémentaires.

Un objet peut maintenant être créé à partir de cette classe avec le nouveau mot-clé :

 let rex = new Animal ('Rex', 4, 'woof');
rex.speak (); // Rex dit "woof"
rex.noise = 'grognement';
rex.speak (); // Rex dit "grogner"

Getters and Setters

Setters sont des méthodes spéciales utilisées pour définir des valeurs uniquement. De même, les Getters sont des méthodes spéciales utilisées pour renvoyer une valeur uniquement. Par exemple:

 classe Animal {

  constructeur (nom = 'anonyme', jambes = 4, bruit = 'rien') {

    this.type = 'animal';
    this.name = nom;
    this.legs = jambes;
    this.noise = bruit;

  }

  parler() {
    console.log (`$ {this.name} dit" $ {this.noise} "`);
  }

  marcher() {
    console.log (`$ {this.name} marche sur $ {this.legs} jambes`);
  }

  // setter
  prendre des repas (nourriture) {
    this.food = nourriture;
  }

  // getter
  Obtenir le dîner() {
    retourner `$ {this.name} mange $ {this.food || «rien»} pour le dîner. »;
  }

}

let rex = nouvel Animal ('Rex', 4, 'woof');
rex.eats = 'n'importe quoi';
console.log (rex.dinner); // Rex mange n'importe quoi pour le dîner.

Enfant ou sous-classes

Il est souvent pratique d'utiliser une classe comme base pour une autre. Une classe Humaine pourrait hériter de toutes les propriétés et méthodes de la classe Animal en utilisant le mot-clé étend . Les propriétés et les méthodes peuvent être ajoutées, supprimées ou modifiées selon les besoins afin que la création d'objets humains devienne plus facile et plus lisible:

 class Human extend Animal {

  constructeur (nom) {

    // appelle le constructeur Animal
    super (nom, 2, «rien d'intéressant»);
    this.type = 'human';

  }

  // remplacer Animal.speak
  parler (à) {

    super.speak ();
    if (to) console.log (`to $ {to}`);

  }

}

super fait référence à la classe parente, il s'agit donc généralement du premier appel effectué dans le constructeur . Dans cet exemple, la méthode Human speak () remplace celle définie dans Animal .

Des instances d'objets de Human peuvent maintenant être créées:

 let don = nouvel humain («Don»);
don.speak («n'importe qui»); // Don ne dit "rien d'intéressant" à personne

don.eats = 'burgers';
console.log (don.dinner); // Don mange des hamburgers pour le dîner.

Méthodes et propriétés statiques

La définition d'une méthode avec le mot-clé statique permet de l'appeler sur une classe sans créer d'instance d'objet. Considérez la constante Math.PI : il n'est pas nécessaire de créer un objet Math avant d'accéder à la propriété PI .

ES6 ne prend pas en charge les propriétés statiques dans de la même manière que les autres langages, mais il est possible d'ajouter des propriétés à la définition de classe elle-même. Par exemple, la classe Humain peut être adaptée pour conserver un décompte du nombre d'objets humains créés:

 classe Humain étend Animal {

  constructeur (nom) {

    // appelle le constructeur Animal
    super (nom, 2, «rien d'intéressant»);
    this.type = 'human';

    // mise à jour du nombre d'objets humains
    Human.count ++;

  }

  // remplacer Animal.speak
  parler (à) {

    super.speak ();
    if (to) console.log (`to $ {to}`);

  }

  // retourne le nombre d'objets humains
  get statique COUNT () {
    return Human.count;
  }

}

// propriété statique de la classe elle-même - pas ses objets
Human.count = 0;

Le getter statique de la classe COUNT renvoie le nombre d'humains en conséquence:

 console.log (`Les humains ont défini: $ {Human.COUNT} '); // Humains définis: 0

let don = new Human ('Don');

console.log (`Humains définis: $ {Human.COUNT}`); // Humains définis: 1

let kim = new Human ('Kim');

console.log (`Humains définis: $ {Human.COUNT}`); // Humains définis: 2

Champs de classe ES2019 (NOUVEAU)

La nouvelle implémentation des champs de classe permet aux propriétés publiques d'être initialisées en haut d'une classe en dehors de tout constructeur:

 classe MyClass {

  a = 1;
  b = 2;
  c = 3;

}

Cela équivaut à:

 classe MyClass {

  constructeur () {
    this.a = 1;
    this.b = 2;
    this.c = 3;
  }

}

Si vous avez toujours besoin d'un constructeur, les initialiseurs seront exécutés avant son exécution.

Champs de classe statiques

Dans l'exemple ci-dessus les propriétés statiques ont été ajoutées de manière non élégante à l'objet de définition de classe après celui-ci. avait été défini. Cela n'est pas nécessaire avec les champs de classe:

 class MyClass {

  x = 1;
  y = 2;
  z statique = 3;

}

console.log (MyClass.z); // 3

Cela équivaut à:

 classe MyClass {

  constructeur () {
    this.x = 1;
    this.y = 2;
  }

}

MyClass.z = 3;

console.log (MyClass.z); // 3

Champs de classe privée

Toutes les propriétés des classes ES6 sont publiques par défaut et peuvent être examinées ou modifiées en dehors de la classe. Dans les exemples Animal ci-dessus, rien n'empêche la modification de la propriété de la nourriture sans appeler le setter mange :

 classe Animal {

  constructeur (nom = 'anonyme', jambes = 4, bruit = 'rien') {

    this.type = 'animal';
    this.name = nom;
    this.legs = jambes;
    this.noise = bruit;

  }

  prendre des repas (nourriture) {
    this.food = nourriture;
  }

  Obtenir le dîner() {
    retourner `$ {this.name} mange $ {this.food || «rien»} pour le dîner. »;
  }

}

let rex = nouvel Animal ('Rex', 4, 'woof');
rex.eats = 'n'importe quoi'; // setter standard
rex.food = 'tofu'; // contourner complètement le setter mange
console.log (rex.dinner); // Rex mange du tofu pour le dîner.

D'autres langues permettent souvent de déclarer des propriétés privées . Ce n'est pas possible dans ES6, donc les développeurs y travaillent souvent en utilisant la convention de soulignement ( _propertyName ), fermetures, symboles ou WeakMaps . Un trait de soulignement fournit un indice au développeur, mais rien ne l'empêche d'accéder à cette propriété.

Dans ES2019, les champs de classe privés sont définis à l'aide d'un hachage # préfixe:

 class MyClass {

  a = 1; // .a est public
  #b = 2; //. # b est privé
  statique #c = 3; //. # c est privé et statique

  incB () {
    ceci. # b ++;
  }

}

soit m = new MyClass ();

m.incB (); // fonctionne OK
m. # b = 0; // erreur - la propriété privée ne peut pas être modifiée en dehors de la classe

Notez qu'il n'y a aucun moyen de définir des méthodes privées, des getters ou des setters. Un TC39 étape 3: le projet de proposition suggère d'utiliser un préfixe de hachage # sur les noms et il a été implémenté à Babel. Par exemple:

 classe MyClass {

  // propriété privée
  #x = 0;

  // méthode privée (ne peut être appelée que dans la classe)
  #incX () {
    cela. # x ++;
  }

  // setter privé (ne peut être utilisé que dans la classe)
  définir #setX (x) {
    cela. # x = x;
  }

  // getter privé (ne peut être utilisé que dans la classe)
  get #getX () {
    retourner ceci. $ x;
  }

}

Les composants React ont souvent des méthodes liées aux événements DOM. Pour garantir que est résolu pour le composant, il est nécessaire de lier chaque méthode en conséquence. Par exemple:

 la classe App étend le composant {

  constructeur () {

    super();

    this.state = {count: 0};

    // lier toutes les méthodes
    this.incCount = this.incCount.bind (this);
  }

  incCount () {
    this.setState (ps => {count: ps.count + 1})
  }

  render () {

    revenir (
      

{this.state.count}

);   } }

Lorsque incCount est défini comme un champ de classe ES2019, il peut être attribué en tant que fonction à l'aide de la flèche grasse ES6 => qui est automatiquement liée à l'objet de définition. Il n'est plus nécessaire d'ajouter les déclarations bind :

 la classe App étend le composant {

  state = {count: 0};

  incCount = () => {
    this.setState (ps => {count: ps.count + 1})
  };

  render () {

    revenir (
      

{this.state.count}

);   } }

Champs de classe: une amélioration?

Les définitions de classe ES6 étaient simplistes. Les champs de classe ES2019 nécessitent moins de code, facilitent la lisibilité et permettent des possibilités de programmation orientées objet intéressantes.

L'utilisation de # pour dénoter la confidentialité a été critiquée, principalement parce qu'elle est laide et ressemble à un hack. La plupart des langues implémentent un mot-clé privé donc toute tentative d'utilisation de ce membre en dehors de la classe sera rejetée par le compilateur.

JavaScript est interprété. Considérez le code suivant:

 class MyClass {
  secret privé = 123;
}

const myObject = new MyClass ();
myObject.secret = 'un-deux-trois';

Cela aurait généré une erreur d'exécution sur la dernière ligne, mais c'est une conséquence grave pour avoir simplement tenté de définir une propriété. JavaScript est volontairement indulgent et ES5 autorise la modification des propriétés sur n'importe quel objet.

Bien que maladroite, la notation # n'est pas valide en dehors d'une définition de classe. Tenter d'accéder à myObject. # Secret peut générer une erreur de syntaxe.

Le débat se poursuivra mais, comme eux ou non, les champs de classe ont été adoptés dans plusieurs moteurs JavaScript. Ils sont là pour rester.






Source link
Quitter la version mobile