Sobes.tech
Junior

Explique comment fonctionne l'héritage en JavaScript.

sobes.tech IA

Réponse de l'IA

L'héritage en JavaScript est implémenté via des prototypes. Chaque objet en JavaScript possède une propriété interne [[Prototype]] qui référence un autre objet. Lorsqu'on tente d'accéder à une propriété ou méthode d'un objet qui n'est pas directement présent, le moteur JavaScript recherche cette propriété ou méthode dans le prototype de cet objet. Si elle n'y est pas, la recherche continue le long de la chaîne de prototypes, formée par les liens [[Prototype]], jusqu'à atteindre null (fin de la chaîne).

Il existe deux mécanismes principaux d'héritage :

  1. Héritage prototype classique (ES5 et antérieur) : Basé sur l'utilisation de fonctions constructrices et leur propriété prototype.

    // Fonction constructeur
    function Animal(name) {
      this.name = name;
    }
    
    // Ajout d'une méthode au prototype
    Animal.prototype.speak = function() {
      console.log(`${this.name} émet un son.`);
    };
    
    // Création d'une instance
    const dog = new Animal('Chien');
    
    // Appel de la méthode du prototype
    dog.speak(); // Affiche : Chien émet un son.
    
    // Le prototype de cat est Animal.prototype
    console.log(Object.getPrototypeOf(dog) === Animal.prototype); // true
    
  2. Héritage basé sur les classes (ES6 et ultérieur) : Utilise la syntaxe class et extends, qui fonctionne en interne avec des prototypes.

    // Classe de base
    class Animal {
      constructor(name) {
        this.name = name;
      }
    
      speak() {
        console.log(`${this.name} émet un son.`);
      }
    }
    
    // Sous-classe héritant de Animal
    class Dog extends Animal {
      constructor(name, breeds) {
        super(name); // Appel du constructeur parent
        this.breeds = breeds;
      }
    
      bark() {
        console.log(`${this.name} aboie.`);
      }
    }
    
    // Création d'une instance de la sous-classe
    const myDog = new Dog('Bublik', ['Labrador', 'Colley']);
    
    // Appel des méthodes de Animal et Dog
    myDog.speak(); // Affiche : Bublik émet un son.
    myDog.bark();  // Affiche : Bublik aboie.
    
    // Le prototype de myDog est Dog.prototype
    console.log(Object.getPrototypeOf(myDog) === Dog.prototype); // true
    
    // Le prototype de Dog.prototype est Animal.prototype
    console.log(Object.getPrototypeOf(Dog.prototype) === Animal.prototype); // true
    

Concepts clés :

  • Chaîne de prototypes : La relation entre objets via leurs [[Prototype]].

  • __proto__ (obsolète/non standard, mais utile pour comprendre) : Propriété permettant d'accéder à [[Prototype]]. Non recommandé en production.

  • Object.getPrototypeOf(obj) : Façon standard d'obtenir le prototype d'un objet.

  • Object.setPrototypeOf(obj, proto) : Façon standard de modifier le prototype d'un objet (non recommandé pour changer le prototype d'objets existants après leur création).

  • instanceof : Opérateur pour vérifier si un objet est une instance d'une classe ou fonction constructeur, en vérifiant sa chaîne de prototypes.

    console.log(myDog instanceof Dog);   // true
    console.log(myDog instanceof Animal); // true
    console.log(myDog instanceof Object); // true (en fin de chaîne, Object.prototype)
    
  • super : Utilisé dans les classes pour appeler des méthodes ou le constructeur de la classe parente.

La différence entre approche classique et basée sur les classes : Les classes offrent une manière plus structurée et syntaxiquement pratique de travailler avec l'héritage prototype, similaire à d'autres langages de programmation. Cependant, le mécanisme fondamental reste le même — héritage via prototypes.