Classes

Les classes JavaScript ont été introduites avec ECMAScript 6. Elles sont un « sucre syntaxique » par rapport à l'héritage prototypal. En effet, cette syntaxe n'introduit pas un nouveau modèle d'héritage dans JavaScript ! Elle fournit uniquement une syntaxe plus simple et plus claire pour créer des objets et manipuler l'héritage.

Définir des classes

En réalité, les classes sont juste des fonctions spéciales. Ainsi, les classes sont définies de la même façon que les fonctions : par déclaration, ou par expression.

Les déclarations de classes

Pour utiliser une déclaration de classe simple, on utilisera le mot-clé class, suivi par le nom de la classe que l'on déclare (ici « Polygone »).

class Polygone {
  constructor(hauteur, largeur) {
    this.hauteur = hauteur;
    this.largeur = largeur;
  }
}

Remontée des déclarations (hoisting)

Les déclarations de fonctions sont remontées dans le code. En revanche, ce n'est pas le cas pour les déclarations de classes. Ainsi, il est nécessaire de déclarer la classe avant de l'instancier. Dans le cas contraire, on obtient une ReferenceError :

var p = new Polygone(); // ReferenceError

class Polygone {}

Les expressions de classes

Il est possible d'utiliser des expressions de classes, nommées ou anonymes. Si on utilise un nom dans l'expression, ce nom ne sera accessible que depuis le corps de la classe.

// anonyme
var Polygone = class {
  constructor(hauteur, largeur) {
    this.hauteur = hauteur;
    this.largeur = largeur;
  }
};

// nommée
var Polygone = class Polygone {
  constructor(hauteur, largeur) {
    this.hauteur = hauteur;
    this.largeur = largeur;
  }
};

Note : Les mêmes règles s'appliquent aux expressions de classes en ce qui concerne la remontée (hoisting) des classes (cf. le paragraphe précédent sur les remontées des déclarations de classe).

Corps d'une classe et définition des méthodes

Le corps d'une classe est la partie contenue entre les accolades. C'est dans cette partie que l'on définit les propriétés d'une classe comme ses méthodes et son constructeur.

Mode strict

Le corps des classes, pour les expressions et pour les déclarations de classes, est exécuté en mode strict.

Constructeur

La méthode constructor est une méthode spéciale qui permet de créer et d'initialiser les objet créés avec une classe. Il ne peut y avoir qu'une seule méthode avec le nom "constructor" pour une classe donnée. Si la classe contient plusieurs occurences d'une méthode constructor, cela provoquera une exception SyntaxError.

Le constructeur ainsi déclaré peut utiliser le mot-clé super afin d'appeler le constructeur de la classe parente.

Méthodes de prototype

Voir aussi les définitions de méthode.

class Polygone {
  constructor(hauteur, largeur) {
    this.hauteur = hauteur;
    this.largeur = largeur;
  }
 
  get area() {
    return this.calcArea();
  }

  calcArea() {
    return this.largeur * this.hauteur;
  }
}

const carré = new Polygone(10, 10);

console.log(carré.area);

Méthodes statiques

Le mot-clé static permet de définir une méthode statique pour une classe. Les méthodes statiques sont appelées par rapport à la classe entière et non par rapport à une instance donnée (ces méthodes ne peuvent pas être appelées « depuis » une instance). Ces méthodes sont généralement utilisées sous formes d'utilitaires au sein d'applications.

class Point {
    constructor(x, y) {
        this.x = x;
        this.y = y;
    }

    static distance(a, b) {
        const dx = a.x - b.x;
        const dy = a.y - b.y;

        return Math.sqrt(dx*dx + dy*dy);
    }
}

const p1 = new Point(5, 5);
const p2 = new Point(10, 10);

console.log(Point.distance(p1, p2));

Créer une sous-classe avec extends

Le mot-clé extends, utilisé dans les déclarations ou les expressions de classes, permet de créer une classe qui hérite d'une autre classe (on parle aussi de « sous-classe » ou de « classe-fille »).

class Animal { 
  constructor(nom) {
    this.nom = nom;
  }
  
  parle() {
    console.log(this.nom + ' fait du bruit.');
  }
}

class Chien extends Animal {
  parle() {
    console.log(this.nom + ' aboie.');
  }
}

Si on déclare un constructeur dans une classe fille, on doit utiiser super() avant this.

On peut également étendre des classes plus traditionnelles basées sur des constructeurs fonctionnels :

function Animal (nom) {
  this.nom = nom;
}
Animal.prototype.crie = function () {
  console.log(this.nom + ' fait du bruit.');
} 

class Chien extends Animal {
  crie() {
    super.crie();
    console.log(this.nom + ' aboie.');
  }
}

var c = new Chien('Ida');
c.crie();
// Ida fait du bruit.
// Ida aboie.

En revanche, les classes ne permettent pas d'étendre des objets classiques non-constructibles. Si on souhaite créer un lien d'héritage en un objet et une classe, on utilisera Object.setPrototypeOf() :

var Animal = {
  crie() {
    console.log(this.nom + ' fait du bruit.');
  }
};

class Chien {
  constructor(nom) {
    this.nom = nom;
  }
  crie() {
    super.crie();
    console.log(this.nom + ' aboie.');
  }
}
Object.setPrototypeOf(Chien.prototype, Animal);

var d = new Chien('Ida');
d.crie();

Le symbole species

Lorsqu'on souhaite renvoyer des objets Array avec une sous-classe MonArray, on peut utiliser symbole species pour surcharger le constructeur par défaut.

Par exemple, si, lorsqu'on utilise des méthodes comme map() qui renvoient le constructeur par défaut et qu'on veut qu'elles renvoient Array plutôt que MonArray, on utilisera Symbol.species :

class MonArray extends Array {
  // On surcharge species
  // avec le constructeur Array du parent
  static get [Symbol.species]() { return Array; }
}
var a = new MonArray(1,2,3);
var mapped = a.map(x => x * x);

console.log(mapped instanceof MonArray); // false
console.log(mapped instanceof Array);    // true

Utiliser super pour la classe parente

Le mot-clé super est utilisé pour appeler les fonctions rattachées à un objet parent.

class Chat { 
  constructor(nom) {
    this.nom = nom;
  }
  
  parler() {
    console.log(this.nom + ' fait du bruit.');
  }
}

class Lion extends Chat {
  parler() {
    super.parler();
    console.log(this.nom + ' rugit.');
  }
}

Les mix-ins

Les sous-classes abstraites ou mix-ins sont des modèles (templates) pour des classes. Une classe ECMAScript ne peut avoir qu'une seule classe parente et il n'est donc pas possible, par exemple, d'hériter de plusieurs classes dont une classe abstraite. La fonctionnalité dont on souhaite disposer doit être fournie par la classe parente.

Une fonction peut prendre une classe parente en entrée et renvoyer une classe fille qui étend cette classe parente. Cela peut permettre d'émuler les mix-ins avec ECMAScript.

var calculetteMixin = Base => class extends Base {
  calc() { }
};

var aleatoireMixin = Base => class extends Base {
  randomiseur() { }
};

Une classe utilisant ces mix-ins peut alors être écrite de cette façon :

class Toto { }
class Truc extends calculetteMixin(aleatoireMixin(Toto)) { }

Spécifications

Spécification État Commentaires
ECMAScript 2015 (6th Edition, ECMA-262)
La définition de 'Class definitions' dans cette spécification.
Standard Définition initiale.
ECMAScript 2017 Draft (ECMA-262)
La définition de 'Class definitions' dans cette spécification.
Projet  

Compatibilité des navigateurs

Fonctionnalité Chrome Firefox (Gecko) Edge Internet Explorer Opera Safari
Support simple

42.0[1]
49.0

45 (45) 13 Pas de support Pas de support 9.0
Fonctionnalité Android Android Webview Firefox Mobile (Gecko) IE Mobile Opera Mobile Safari Mobile Chrome pour Android
Support simple Pas de support 42.0 45.0 (45) ? ? 9

42.0[1]
49.0

[1] Le mode strict est nécessaire, pour que cela fonctionne en mode non-strict, il faut activer l'option « Activer le JavaScript expérimental » (par défaut elle est désactivée).

Voir aussi

Étiquettes et contributeurs liés au document

 Contributeurs à cette page : SphinxKnight, rgranger, blackholegalaxy, Yukulele.
 Dernière mise à jour par : SphinxKnight,