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