Avez-vous une question? (216) 97 656 803 hajjriadh@gmail.com
JavaScript

L'héritage des classes (extends et super)

L'héritage des classes (extends et super). Dans cette leçon du cours JavaScript, vous apprendrez à : créer une classe enfant avec extends ; appeler le constructeur parent avec super() ; redéfinir une ...

0 chapitres 0 QCM Accès gratuit
Dans cet article

À propos de ce cours

L'héritage des classes (extends et super). Dans cette leçon du cours JavaScript, vous apprendrez à : créer une classe enfant avec extends ; appeler le constructeur parent avec super() ; redéfinir une méthode et réutiliser la version du parent avec super.methode() ; savoir quand l'héritage est adapté (relation « est un »).

Chapitre 16 — La programmation orientée objet · 16.5 L'héritage des classes (extends et super)

🎯 Objectifs de la leçon
• créer une classe enfant avec extends;
• appeler le constructeur parent avec super();
• redéfinir une méthode et réutiliser la version du parent avec super.methode();
• savoir quand l'héritage est adapté (relation « est un »).

1. Pourquoi hériter ?

Un livre papier et un e-book sont tous deux des produits: ils ont un nom, un prix HT, un prix TTC. Mais le livre a un poids et des frais de livraison, l'e-book une taille de fichier. Plutôt que de recopier ce qui est commun, on écrit une classe parent Produit et des classes enfants qui en héritent.

Hiérarchie Produit, ProduitPhysique et ProduitNumerique
Figure 1 — Une classe parent, deux classes enfants.

2. extends et super

class Produit {
  constructor(nom, prixHT) {
    this.nom = nom;
    this.prixHT = prixHT;
  }
  get prixTTC() {
    return Math.round(this.prixHT * 1.19 * 100) / 100;
  }
  description() {
    return `${this.nom} — ${this.prixTTC} DT`;
  }
}

// ProduitPhysique HÉRITE de Produit : il a tout ce que Produit a, plus le poids
class ProduitPhysique extends Produit {
  constructor(nom, prixHT, poidsKg) {
    super(nom, prixHT); // appelle le constructeur du parent : OBLIGATOIRE avant this
    this.poidsKg = poidsKg;
  }
  get fraisLivraison() {
    return 5 + 2 * this.poidsKg;
  }
  // REDÉFINITION (override) : on complète la méthode du parent
  description() {
    return `${super.description()} + livraison ${this.fraisLivraison} DT`;
  }
}

class ProduitNumerique extends Produit {
  constructor(nom, prixHT, tailleMo) {
    super(nom, prixHT);
    this.tailleMo = tailleMo;
  }
  description() {
    return `${super.description()} (téléchargement ${this.tailleMo} Mo)`;
  }
}

const livre = new ProduitPhysique("Livre JavaScript", 40, 1.2);
const ebook = new ProduitNumerique("E-book JavaScript", 20, 8);

console.log(livre.description());
console.log(ebook.description());
console.log("livre est un ProduitPhysique ?", livre instanceof ProduitPhysique);
console.log("livre est un Produit ?", livre instanceof Produit);
console.log("ebook est un ProduitPhysique ?", ebook instanceof ProduitPhysique);
console.log("Prix TTC hérité :", ebook.prixTTC);

Résultat dans la console

Livre JavaScript — 47.6 DT + livraison 7.4 DT
E-book JavaScript — 23.8 DT (téléchargement 8 Mo)
livre est un ProduitPhysique ? true
livre est un Produit ? true
ebook est un ProduitPhysique ? false
Prix TTC hérité : 23.8
  • class Enfant extends Parent: l'enfant reçoit toutes les propriétés, méthodes, getters et membres statiques du parent.
  • super(…) dans le constructeur appelle le constructeur du parent. C'est obligatoire, et avant d'utiliser this.
  • Redéfinir (override) une méthode : on l'écrit à nouveau dans l'enfant, avec le même nom.
  • super.description() appelle la version du parent, pour la compléter au lieu de la réécrire entièrement.
  • Une instance enfant est aussi une instance du parent : livre instanceof Produit vaut true.

3. Oublier super()

class Animal {
  constructor(nom) {
    this.nom = nom;
  }
}
class Chien extends Animal {
  constructor(nom, race) {
    this.race = race; // ✗ this utilisé AVANT super()
    super(nom);
  }
}
try {
  new Chien("Rex", "berger");
} catch (e) {
  console.log(e.constructor.name + " :", e.message);
}

Résultat dans la console

ReferenceError : Must call super constructor in derived class before accessing 'this' or returning from derived constructor

4. Quand utiliser l'héritage ?

Posez-vous la question : « X est un Y ? » Un livre est un produit : héritage possible. Une voiture est un moteur ? Non, elle a un moteur : on utilise alors la composition (leçon 16.7).

Évitez les hiérarchies profondes (plus de deux ou trois niveaux) : chaque changement du parent se répercute sur tous les descendants. Un champ privé #x du parent n'est pas accessible dans l'enfant : celui-ci passe par les getters et méthodes publics du parent.

ℹ️ À retenir
• class Enfant extends Parent: l'enfant hérite de tout le parent.
• super(…) est obligatoire dans le constructeur de l'enfant, avant tout this.
• Redéfinir une méthode = la réécrire dans l'enfant ; super.methode() appelle la version du parent.
• Héritage si « est un » ; sinon, composition (« a un »).
• Les champs #privés du parent restent inaccessibles à l'enfant.

🛠 Activité 5 — Une famille de comptes bancaires

Mission : Créez des comptes spécialisés à partir de votre CompteBancaire de l'activité 4.

Questions pour avancer (répondez dans votre compte rendu, puis appliquez dans votre projet) :

  1. Créez CompteEpargne extends CompteBancaire avec un taux d'intérêt et une méthode ajouterInterets(). Pouvez-vous écrire this.#solde dans CompteEpargne? Comment faire autrement ?
  2. Un compte épargne interdit les retraits de plus de 1 000 DT. Redéfinissez retirer en réutilisant la version du parent avec super. Pourquoi est-ce mieux que de recopier le code ?
  3. Créez CompteCourant qui autorise un découvert. Le parent refuse un solde négatif : quelle méthode du parent faudrait-il rendre plus souple ? Que pensez-vous de cette situation ?
  4. Retirez l'appel à super() dans un constructeur. Quel message obtenez-vous ? Et si vous l'appelez après this.taux = …?
  5. CompteEpargne hérite-t-il des membres statiques de CompteBancaire? Vérifiez avec un compteur statique.
  6. Un étudiant propose class Client extends CompteBancaire, parce qu'un client a un compte. Que lui répondez-vous ?

Je vérifie / je rends :

  • ☐ Les trois classes et un fichier de démonstration.
  • ☐ Votre réponse argumentée à la question 6.

← 16.4 L'encapsulation : les champs et méthodes privés (#)16.6 Les prototypes : ce qui se cache derrière les classes →