Fermer

juin 4, 2018

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


ES6 a introduit les classes dans JavaScript, mais elles sont trop simplistes pour les 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 à TC39 étape 3: candidate et pourrait apparaître dans ES2019 (ES10).

Un récapitulatif rapide des classes ES6 est utile avant d'examiner les champs de classe plus en détail.

Classe ES6 Notions de base

Le modèle d'héritage prototypique de JavaScript peut sembler déroutant aux développeurs avec une compréhension de l'héritage classique utilisé dans des langages tels que C ++, C #, Java et PHP. Les classes JavaScript sont principalement du sucre syntaxique, mais elles offrent des concepts de programmation orientés objet plus familiers.

Une classe est un modèle qui définit comment les objets de ce type se comportent. La classe Animal suivante définit les animaux génériques (les classes sont normalement notées avec un capital initial pour les distinguer des objets et autres types):

 class Animal {

  constructeur (name = '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} "`);
  }

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

}

Les déclarations de classe s'exécutent en mode strict; inutile d'ajouter 'use strict' .

Une méthode de constructeur est exécutée lorsqu'un objet de ce type est créé et définit généralement les propriétés initiales. speak () et walk () sont des méthodes qui ajoutent d'autres fonctionnalités

Un objet peut maintenant être créé à partir de cette classe avec le nouveau mot-clé : [19659006] const rex = nouvel animal ('Rex', 4, 'woof');
rex.speak (); // Rex dit "woof"
rex.noise = 'growl';
rex.speak (); // Rex dit "grogner"

Getters et Setters

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

 class Animal {

  constructeur (name = '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} "`);
  }

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

  // setter
  set mange (nourriture) {
    this.food = nourriture;
  }

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

}


const 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. Si nous créons principalement des objets-chiens, Animal est trop générique, et nous devons spécifier les mêmes valeurs par défaut de 4-leg et de "woof"

Dog peut hériter toutes les propriétés et méthodes de la classe Animal en utilisant étend . Les propriétés et méthodes spécifiques au chien peuvent être ajoutées ou supprimées si nécessaire:

 class Dog extends Animal {

  constructeur (nom) {

    // appelle le constructeur Animal
    super (nom, 4, 'woof');
    this.type = 'chien';

  }

  // remplacer Animal.speak
  parler (à) {

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

  }

}

super fait référence à la classe parent et est généralement appelé dans le constructeur . Dans cet exemple, la méthode Dog speak () remplace celle définie dans Animal .

Des instances d'objet de Dog peuvent maintenant être créées:

 const rex = nouveau chien ('Rex');
rex.speak ('tout le monde'); // Rex dit "woof" à tout le monde

rex.eats = 'n'importe quoi';
console.log (rex.dinner); // Rex mange n'importe quoi 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. JavaScript ne supporte pas les propriétés statiques de la même manière que les autres langages, mais il est possible d'ajouter des propriétés à la définition de la classe (une classe est un objet JavaScript en soi!).

] La classe Dog peut être adaptée pour retenir le nombre d'objets dog créés:

 class Dog extends Animal {

  constructeur (nom) {

    // appelle le constructeur Animal
    super (nom, 4, 'woof');
    this.type = 'chien';

    // met à jour le nombre d'objets Chien
    Dog.count ++;

  }

  // remplacer Animal.speak
  parler (à) {

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

  }

  // renvoie le nombre d'objets chien
  static obtient COUNT () {
    retourner Dog.count;
  }

}

// propriété statique (ajoutée après la définition de la classe)
Dog.count = 0;

Le getter COUNT statique de la classe renvoie le nombre de chiens créés:

 console.log (`Dogs defined: $ {Dog.COUNT}`); // Chiens définis: 0

const don = new Chien ('Don');

console.log (`Dogs defined: $ {Dog.COUNT}`); // Chiens définis: 1

const kim = nouveau chien ('Kim');

console.log (`Dogs defined: $ {Dog.COUNT}`); // Chiens définis: 2

Pour plus d'informations, reportez-vous à JavaScript orienté objet: Plongée profonde dans les classes ES6 .

Champs de classe ESnext

La proposition de champs de classe permet d'initialiser les propriétés en haut d'un class:

 classe MyClass {

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

}

Ceci est équivalent à:

 class MyClass {

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

}

Les initialiseurs sont exécutés avant tout constructeur ( en supposant qu'un constructeur est toujours nécessaire ).

Champs de classes statiques

Les champs de classe permettent de déclarer des propriétés statiques dans la classe ] Par exemple:

 class MyClass {

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

}

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

L'équivalent ES6 inélégant:

 class 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 l'exemple Animal ci-dessus, rien n'empêche que la propriété food soit changée sans appeler le setter mange :

 class Animal {

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

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

  }

  set mange (nourriture) {
    this.food = nourriture;
  }

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

}

const rex = nouvel animal ('Rex', 4, 'woof');
rex.eats = 'n'importe quoi'; // setter standard
rex.food = 'tofu'; // contournent le setters de mange tout à fait
console.log (rex.dinner); // Rex mange du tofu pour le dîner.

D'autres langues permettent de déclarer private propriétés. Ce n'est pas possible dans ES6, bien que les développeurs puissent le contourner en utilisant une convention de soulignement ( _propertyName ), fermetures, symboles ou WeakMaps .

Dans ESnext, les champs de classe privés sont définis en utilisant un hash # 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 ++;
  }

}

const m = nouveau MyClass ();

m.incB (); // fonctionne bien
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 et des setters, bien qu'un TC39 stage 2: draft proposition suggère d'utiliser un préfixe hash # sur les noms. Par exemple:

 class MyClass {

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

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

  // setter privé (ne peut être appelé que dans la classe)
  set #setX (x) {
    ceci. # x = x;
  }

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

}

Les composants React ont souvent des méthodes liées aux événements DOM. Pour assurer que résout le composant, il faut lier toutes les méthodes en conséquence. Par exemple:

 class App extends Component {

  constructeur () {

    super();

    état = {nombre: 0};

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

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

  render () {

    revenir (
      

{this.state.count}

);   } }

Si incCount est défini comme un champ de classe, il peut être défini sur une fonction à l'aide d'une grosse flèche ES6 => qui le lie automatiquement à l'objet de définition. L'état peut également être déclaré en tant que champ de classe, donc aucun constructeur n'est requis:

 class App extends Component {

  état = {nombre: 0};

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

  render () {

    revenir (
      

{this.state.count}

);   } }

Utilisation de champs de classe aujourd'hui

Les champs de classe ne sont actuellement pas pris en charge dans les navigateurs ou Node.js. Cependant, il est possible de transpiler la syntaxe en utilisant Babel qui est activé par défaut en utilisant Create React App . Alternativement, Babel peut être installé et configuré en utilisant les commandes de terminal suivantes:

 mkdir class-properties
cd class-properties
npm init -y
npm installer --save-dev babel-cli babel-plugin-transform-class-properties
echo '{"plugins": ["transform-class-properties"]}'> .babelrc

Ajouter une commande build à la section scripts de package.json :

 "scripts": {
  "build": "babel in.js -o out.js"
},

Puis lancez avec npm run build pour transférer le fichier ESnext in.js vers un fichier compatible avec le navigateur croisé out.js .

Babel support pour méthodes privées, getters et setters a été proposé

Champs de classe: une amélioration?

Les définitions de classe ES6 étaient simplistes. Les champs de classe devraient faciliter la lisibilité et permettre certaines options intéressantes. Je n'aime pas particulièrement utiliser un hash # pour désigner des membres privés, mais des comportements inattendus et des problèmes de performances seraient encourus sans cela (voir les nouveaux champs #private de JavaScript pour un explication]

Peut-être que cela va de soi, mais je vais le dire quand même: les concepts discutés dans cet article sont sujets à changement et ne pourront jamais être implémentés! avoir des avantages pratiques et l'intérêt augmente. C'est un pari sûr.






Source link