Héritage de classes JavaScript
Apprenez l'héritage de classes JavaScript avec extends et super : la chaîne de prototypes, la surcharge de méthodes, super(), les classes natives et les méthodes statiques.
Introduction à l'héritage de classes JavaScript
L'héritage de classes est un concept fondamental de la programmation orientée objet qui permet à une classe d'hériter des propriétés et des méthodes d'une autre classe. En JavaScript, l'héritage de classes est implémenté à l'aide du mot-clé extends, offrant un moyen de créer une classe dérivée qui hérite d'une classe de base.
Pour plus d'informations sur la syntaxe de base, consultez JavaScript : Classes et syntaxe de base.
Ce chapitre explique comment créer des classes dérivées, surcharger des méthodes et des propriétés, appeler le parent avec super, étendre des classes natives comme Array, et hériter de méthodes statiques — ainsi que la chaîne de prototypes qui rend tout cela possible en coulisses.
Fonctionnement de l'héritage : la chaîne de prototypes
Le mot-clé class est du sucre syntaxique par-dessus l'héritage prototypal de JavaScript. Lorsque vous écrivez class Circle extends Shape, le moteur établit deux liens :
Circle.prototype.__proto__ === Shape.prototype— ainsi les méthodes d'instance remontent la chaîne.Circle.__proto__ === Shape— ainsi les méthodes statiques sont également héritées.
Lorsque vous lisez une propriété ou appelez une méthode sur un object, le moteur regarde d'abord l'object lui-même. Si elle n'est pas trouvée, il remonte la chaîne de prototypes — vers Circle.prototype, puis Shape.prototype, puis Object.prototype, puis null — en s'arrêtant à la première correspondance. C'est précisément pour cela qu'une instance de Circle peut appeler une méthode définie sur Shape.
Object.getPrototypeOf(obj) retourne le maillon suivant dans la chaîne (la façon standard et préconisée de l'inspecter). L'accesseur historique obj.__proto__ pointe vers le même object. Comprendre cette chaîne explique tout ce qui suit : la surcharge fonctionne parce qu'un prototype plus proche masque un prototype plus éloigné, et super fonctionne parce qu'il saute explicitement au prototype parent.
Créer une classe dérivée
Pour créer une classe qui hérite d'une autre, on utilise le mot-clé extends :
Dans cet exemple, Circle étend Shape, ce qui signifie qu'elle hérite des propriétés et méthodes de Shape, tout en fournissant ses propres méthodes. Notez que Circle ne définit pas son propre constructeur. En JavaScript, les classes dérivées sans constructeur explicite appellent automatiquement super() avec les mêmes arguments passés au constructeur de la classe dérivée.
Surcharger des méthodes
Les classes dérivées peuvent surcharger les méthodes de leurs classes de base pour fournir un comportement spécifique à la sous-classe.
Ici, Circle surcharge la méthode print pour refléter son type spécifique.
Appeler les méthodes parentes avec super
Vous pouvez également appeler une méthode de la classe parente depuis la classe dérivée en utilisant super.methodName(). C'est utile lorsque vous souhaitez étendre le comportement du parent plutôt que de le remplacer complètement.
Ici, super.print() exécute la logique du parent avant d'ajouter la sortie spécifique à la sous-classe.
Un exemple concret de surcharge : calculer une aire
La surcharge est particulièrement utile lorsque chaque sous-classe a besoin d'un comportement vraiment différent. Ici, une Shape de base définit l'interface partagée, et chaque sous-classe surcharge area() avec son propre calcul. L'appel de area() sur un Circle se résout vers Circle.prototype.area, qui masque la version de base.
Notez que describe() est défini uniquement sur Shape, pourtant il appelle this.area() et obtient l'implémentation de la sous-classe. C'est la chaîne de prototypes à l'œuvre : this fait toujours référence à l'instance réelle, donc la recherche de méthode commence à partir de Circle ou Rectangle.
Surcharger des propriétés et lire super.prop
super n'est pas limité aux méthodes — vous pouvez lire une propriété définie sur le prototype parent avec super.prop, ce qui est pratique quand une sous-classe veut s'appuyer sur le getter d'un parent plutôt que de le remplacer.
Accéder au constructeur parent : le mot-clé super
Lorsqu'une classe étend une autre classe, le constructeur de la classe dérivée doit appeler le constructeur du parent avec super() avant de pouvoir utiliser this. Voici comment super est utilisé dans les constructeurs pour s'assurer que la classe parente est initialisée :
Pourquoi super() doit s'exécuter avant this
Dans une classe dérivée, l'instance n'est pas créée tant que super() ne s'est pas exécuté — c'est le travail du constructeur parent. Jusqu'alors, this est dans un état non initialisé, donc y accéder (lire, assigner, ou même retourner l'object implicitement) lance une ReferenceError. Il s'agit d'une règle du langage, non d'une préférence de style.
Une règle connexe : si une classe dérivée définit un constructeur, elle doit appeler super() quelque part avant de se terminer, ou la même ReferenceError est lancée. (Une classe dérivée sans constructeur explicite convient — JavaScript insère constructor(...args) { super(...args); } pour vous.) Une fois que super() retourne, this est entièrement initialisé et prêt à l'emploi.
Hériter des méthodes statiques
Les membres statiques appartiennent à la classe elle-même, pas aux instances. Parce que extends lie également Circle.__proto__ à Shape, les classes dérivées héritent des méthodes statiques et peuvent les appeler directement. Pour plus d'informations sur leur déclaration, consultez Propriétés et méthodes statiques JavaScript.
À l'intérieur d'une méthode statique, this fait référence à la classe sur laquelle elle a été invoquée, donc Shape.create appelé en tant que Circle.create construit un Circle.
Héritage multi-niveaux
Les chaînes peuvent avoir plus de deux niveaux. La recherche de méthode remonte simplement plus loin dans la chaîne de prototypes, et super fait toujours référence au prototype un niveau au-dessus de la classe où la méthode est définie.
Étendre les classes natives
Vous pouvez étendre des classes natives telles que Array, Error ou Map pour créer des versions spécialisées qui conservent tout le comportement natif tout en ajoutant le vôtre.
Le piège de Symbol.species. Les méthodes comme map, filter et slice retournent une nouvelle collection. Par défaut, elles retournent une instance de votre sous-classe (MyArray), pas un Array ordinaire — ce qui est généralement correct, mais peut surprendre du code qui attend un vrai Array. Vous pouvez revenir aux tableaux ordinaires en surchargeant le getter statique Symbol.species.
Pour combiner des comportements provenant de plusieurs sources (JavaScript ne prend pas en charge l'héritage multiple), consultez Les mixins JavaScript.
Résumé
Points clés à retenir :
- Utilisez
extendspour dériver une classe ; cela lie à la fois la chaîne de prototypes (méthodes d'instance) et la classe elle-même (méthodes statiques) au parent. - La recherche de méthode et de propriété remonte la chaîne de prototypes en s'arrêtant à la première correspondance — c'est pourquoi une définition plus proche surcharge une définition plus éloignée. Inspectez la chaîne avec
Object.getPrototypeOf(). - Dans un constructeur dérivé, appelez
super()avantthis. Tant quesuper()ne s'est pas exécuté, l'instance n'est pas initialisée et toute utilisation dethislance uneReferenceError. - Accédez explicitement au comportement parent avec
super.method()ousuper.prop, même si vous l'avez surchargé. - Vous pouvez étendre les classes natives comme
Array— faites simplement attention au comportement deSymbol.specieslorsque les méthodes retournent de nouvelles collections.
Prochaines étapes :
- Héritage prototypal JavaScript — le mécanisme sur lequel les classes sont construites.
- Propriétés et méthodes statiques JavaScript — déclarer et hériter des membres statiques.
- Les mixins JavaScript — réutiliser des comportements entre des classes non liées sans chaîne d'héritage unique.