En langage orientĂ© objet, une classe est un modĂšle de code programme extensible servant Ă crĂ©er des objets. Elle fournit les valeurs initiales de lâĂ©tat (les variables membres) et de lâimplĂ©mentation du comportement (les fonctions ou mĂ©thodes membres).
En pratique, nous avons souvent besoin de crĂ©er beaucoup dâobjets de mĂȘme type, tels que des utilisateurs, des biens ou toute autre chose.
Comme nous le savons dans le chapitre Le constructeur, l'opérateur "new", new function peut nous aider à faire cela.
Mais dans le JavaScript moderne, il y a une construction de la âclasseâ plus avancĂ©e qui introduit de nombreux nouveaux aspects utiles en langage orientĂ© objet.
La syntaxe de âclasseâ
La syntaxe de base est :
class MyClass {
// Les méthodes de la classe
constructor() { ... }
method1() { ... }
method2() { ... }
method3() { ... }
...
}
Vous pouvez ensuite utiliser new MyClass() pour créer un nouvel objet ayant toute la liste des méthodes.
La mĂ©thode constructor() est automatiquement appelĂ©e par new, donc nous pouvons initialiser lâobjet Ă ce niveau.
Par exemple :
class User {
constructor(name) {
this.name = name;
}
sayHi() {
alert(this.name);
}
}
// Usage:
let user = new User("John");
user.sayHi();
Lorsque new User("John") est appelé :
- Un nouvel objet est créé.
- Le
constructorsâexĂ©cute avec les arguments qui lui sont passĂ©s et assignethis.namea lâobjet.
âŠensuite nous pouvons appeler les mĂ©thodes de lâobjet, tel que user.sayHi().
Un piÚge fréquent des développeurs novices est de mettre une virgule entre les méthodes de la classe, entrainant ainsi une erreur syntaxique.
La notation ici ne doit pas ĂȘtre confondue avec les objets littĂ©raux. A lâintĂ©rieure dâune classe, aucune virgule nâest requise.
Quâest-ce quâune classe ?
Alors, câest quoi exactement une class ? Ce nâest pas totalement une nouvelle entitĂ© au niveau du langage, comme on pourrait le penser.
DĂ©voilons maintenant la magie et regardons ce quâest rĂ©ellement une classe. Cela va nous aider Ă comprendre plusieurs aspects complexes.
En JavaScript, une classe est une sorte de fonction.
Regardons ici :
class User {
constructor(name) { this.name = name; }
sayHi() { alert(this.name); }
}
// La preuve : User est une fonction
alert(typeof User); // function
Ce que la construction de la classe classe User {...} fait rĂ©ellement, câest :
- Créer une fonction nommée
User, qui devient le rĂ©sultat de la dĂ©claration de la classe. Le code de la fonction est tirĂ©e de la mĂ©thodeconstructor(considĂ©rĂ©e comme Ă©tant vide au cas ou cette mĂ©thode nâest pas Ă©crite). - Garde les mĂ©thodes de la classe, telle que
sayHi, dansUser.prototype.
AprĂšs la crĂ©ation de new User, lorsque nous appelons sa mĂ©thode, elle est extraite du prototype, comme dĂ©crit dans le chapitre F.prototype. Donc, lâobjet a accĂšs aux mĂ©thodes de classe.
Nous pouvons illustrer le résultat de la déclaration de class User ainsi :
Voici le code pour une introspection :
class User {
constructor(name) { this.name = name; }
sayHi() { alert(this.name); }
}
// classe est une fonction
alert(typeof User); // function
// ...ou, plus précisément, le constructeur de la méthode
alert(User === User.prototype.constructor); // true
// Les méthodes sont dans User.prototype, par exemple :
alert(User.prototype.sayHi); // le code de la méthode sayHi
// Il y a exactement deux méthodes dans le prototype
alert(Object.getOwnPropertyNames(User.prototype)); // constructeur, sayHi
Pas simplement un sucre syntaxique
Parfois certaines personnes disent que la notion de class est un âsucre syntaxiqueâ (une syntaxe qui est destinĂ©e Ă rendre la lecture plus facile, mais elle nâintroduit rien de nouveau), parce quâen rĂ©alitĂ© nous pouvons dĂ©clarer la mĂȘme chose sans utiliser le mot clĂ© class :
// Réécriture de class User en fonctions pures
// 1. Créer la fonction constructeur
function User(name) {
this.name = name;
}
// un prototype de fonction a une propriété constructeur par défaut,
// nous n'avons donc pas besoin de le créer
// 2. Ajouter la méthode au prototype
User.prototype.sayHi = function() {
alert(this.name);
};
// Usage:
let user = new User("John");
user.sayHi();
Le rĂ©sultat de cette dĂ©finition est Ă peu prĂšs la mĂȘme chose. Donc, il y a bien des raisons de vouloir considĂ©rer class comme pouvant ĂȘtre un sucre syntaxique pour dĂ©finir un constructeur ensemble avec ses mĂ©thodes de prototype.
Cependant, il existe des différences importantes.
-
PremiÚrement, une fonction créée par
classest labellisĂ©e par une propriĂ©tĂ© interne spĂ©ciale[[IsClassConstructor]]: true. Ce nâest donc pas tout Ă fait la mĂȘme chose que de le crĂ©er manuellement.Le langage vĂ©rifie cette propriĂ©tĂ© Ă divers endroits. Par exemple, contrairement Ă une fonction rĂ©guliĂšre, elle doit ĂȘtre appelĂ©e avec
new:class User { constructor() {} } alert(typeof User); // fonction User(); // Erreur: le constructeur Class User ne peut ĂȘtre invoque sans 'new'Aussi, la reprĂ©sentation en chaĂźne de caractĂšres dâun constructeur de class dans la plupart des moteurs de JavaScript commence avec âclassâŠâ :
class User { constructor() {} } alert(User); // class User { ... }Il y a dâautres diffĂ©rences, nous les verrons bientĂŽt.
-
Les méthodes de Class sont non-énumérable. Une définition de la classe attribue
falseĂ la propriĂ©tĂ©enumerablepour toutes les mĂ©thodes du"prototype".Câest bien, parce que si nous exĂ©cutons un
for..insur un Object, souvent nous ne voulons pas accéder aux méthodes de sa classe. -
Les Classes utilisent toujours
use strict. Tout code Ă lâintĂ©rieur de la construction de la classe est automatiquement en mode strict.
En outres, la syntaxe classe apporte beaucoup dâautres caractĂ©ristiques que nous allons explorer plus tard.
LâExpression Class
Tout comme les fonctions, les classes peuvent ĂȘtre dĂ©finies a lâintĂ©rieur dâune autre expression, passĂ©es en paramĂštres, retournĂ©es, assignĂ©es etc.
Voici un exemple dâexpression dâune classe :
let User = class {
sayHi() {
alert("Hello");
}
};
Similairement aux Fonction Expressions nommées, les expressions de classe peuvent avoir un nom.
Si une expression de classe a un nom, il est visible Ă lâintĂ©rieur de la classe uniquement :
// "Expression de Classe nommée"
// (Terme non existant dans la spécification, mais elle est similaire a une Expression de Fonction nommée)
let User = class MyClass {
sayHi() {
alert(MyClass); // le nom MyClass est seulement visible dans la classe
}
};
new User().sayHi(); // ça fonctionne, montre la définition de MyClass
alert(MyClass); // erreur, le nom MyClass n'est pas visible en dehors de la classe
Nous pouvons mĂȘme crĂ©er les classes dynamiquement âĂ la demandeâ, comme suit :
function makeClass(phrase) {
// déclare une classe et la retourne
return class {
sayHi() {
alert(phrase);
}
};
}
// Crée une nouvelle classe
let User = makeClass("Hello");
new User().sayHi(); // Hello
Accesseurs/Mutateurs
Tout comme les objets littéraux, les classes peuvent inclure des accesseurs/mutateurs, des propriétés évaluées etc.
Voici un exemple pour user.name implémenté en utilisant les propriétés get/set :
class User {
constructor(name) {
// invoque l'accesseur (the setter)
this.name = name;
}
get name() {
return this._name;
}
set name(value) {
if (value.length < 4) {
alert("Name is too short.");
return;
}
this._name = value;
}
}
let user = new User("John");
alert(user.name); // John
user = new User(""); // le nom est trop court.
Techniquement, une telle déclaration de classe fonctionne en créant des getters et des setters dans User.prototype.
Computed names [âŠ]
Voici un exemple avec un nom de méthode calculé utilisant des crochets [...] :
class User {
['say' + 'Hi']() {
alert("Hello");
}
}
new User().sayHi();
Ces caractĂ©ristiques sont faciles Ă retenir, car elles ressemblent Ă celles dâobjets littĂ©raux.
Champs de classe
Les propriétés de classe sont un ajout récent au langage.
Auparavant, nos classes nâavaient que des mĂ©thodes.
Les âClass fieldsâ (champs de classe) sont une syntaxe qui permet dâajouter des propriĂ©tĂ©s.
Par exemple, ajoutons la propriété name à class User :
class User {
name = "John";
sayHi() {
alert(`Hello, ${this.name}!`);
}
}
new User().sayHi(); // Hello, John!
Il suffit donc dâĂ©crire â
La diffĂ©rence importante des champs de classe est quâils sont dĂ©finis sur des objets individuels, et non sur User.prototype :
class User {
name = "John";
}
let user = new User();
alert(user.name); // John
alert(User.prototype.name); // undefined
Nous pouvons Ă©galement attribuer des valeurs Ă lâaide dâexpressions et dâappels de fonctions plus complexes :
class User {
name = prompt("Name, please?", "John");
}
let user = new User();
alert(user.name); // John
Création de méthodes liées avec des champs de classe
Comme dĂ©montrĂ© dans le chapitre Le "bind" de fonction les fonctions en JavaScript ont un this dynamique. Cela dĂ©pend du contexte de lâappel.
Donc, si une méthode objet est contournée et appelée dans un autre contexte, this ne sera plus une référence à son objet.
Par exemple, ce code affichera undefined :
class Button {
constructor(value) {
this.value = value;
}
click() {
alert(this.value);
}
}
let button = new Button("hello");
setTimeout(button.click, 1000); // undefined
Le problĂšme est appelĂ© âperdre le thisâ.
Il existe deux approches pour le corriger, comme indiqué dans le chapitre Le "bind" de fonction :
- Passer une fonction wrapper, telle que
setTimeout(() => button.click(), 1000). - Lier la mĂ©thode Ă lâobjet, par exemple dans le constructeur.
Les champs de classe fournissent une syntaxe plus élégante :
class Button {
constructor(value) {
this.value = value;
}
click = () => {
alert(this.value);
}
}
let button = new Button("hello");
setTimeout(button.click, 1000); // hello
Le champ de classe click = () => {...} est créé par objet, il y a une fonction distincte pour chaque objet Button, avec this Ă lâintĂ©rieur rĂ©fĂ©rençant cet objet. Nous pouvons passer button.click nâimporte oĂč, et la valeur de this sera toujours correcte.
Câest particuliĂšrement utile dans un environnement de navigateur, pour les Ă©couteurs dâĂ©vĂ©nements.
Résumé
La syntaxe de base dâune classe ressemble Ă ceci :
class MyClass {
prop = value; // propriété
constructor(...) { // constructeur
// ...
}
method(...) {} // méthode
get something(...) {} // méthode définie avec un accesseur
set something(...) {} // méthode définie avec un mutateur
[Symbol.iterator]() {} // méthode avec un nom évalué (symbole ici)
// ...
}
MyClass est techniquement une fonction (celle que nous fournissons en tant que constructor), tandis que les méthodes, accesseurs et mutateurs sont écrits dans MyClass.prototype.
Dans les prochains chapitres nous apprendrons plus Ă propos des classes, y compris la notion dâhĂ©ritage et les autres caractĂ©ristiques.
Commentaires
<code>, pour plusieurs lignes â enveloppez-les avec la balise<pre>, pour plus de 10 lignes - utilisez une sandbox (plnkr, jsbin, codepenâŠ)