Faire un héritage propre en Javascript

Cet article a été publié depuis plus de 6 mois, cela signifie que le contenu peut ne plus être d'actualité.

Plus je m'intéresse au langage Javascript et plus je me rends compte des erreurs que je fais depuis maintenant des années. En fait bien peu de développeurs connaissent réellement ce langage. A tel point que très peu de personne (moi inclus) savent écrire un héritage sans passer par composant tier.

Car en attendant de pouvoir utiliser ECMAScript 6 et ainsi de bénéficier des mots-clés class et extend, écrire un héritage en Javascript n'est pas trivial. Pour comprendre comment réaliser cette opération, il vous faudra tout d'abord connaître la notion de prototype Javascript.

En ECMAScript 5 (version actuellement supportée par la majorité des navigateurs), le moyen le plus simple de réaliser un héritage est d'utiliser la fonction Object.create. Ainsi si j'ai une classe Cat qui doit hériter d'une classe Animal, on peut cela l'héritage ainsi :

function Animal(p1, p2) {
  // ...
}

function Cat(p1, p2, p3) {
  Animal.call(this, p1, p2); // super() => appel du constructeur parent
  this.myProp = p3;

  // ...
}

Cat.prototype = Object.create(Animal.prototype, {
  constructor: { value: Cat }
});

De cette manière la classe Cat va hériter du comportement de la classe Animal.

Mais il se peut pour une raison quelconque vous utilisiez un navigateur ne supportant pas la version 5 de Javascript. Dans ce cas-là, il vous faudra écrire manuellement l'héritage.

On pourrait alors être tenté d'écrire quelque chose comme Child.prototype = new Parent() ce qui reviendrait à mettre dans le prototype de Child toutes les méthodes de Parent.

Tout d'abord écrire cette ligne de code n'est pas anodin, car cela signifie pour écrire un héritage, vous devez instancier un objet (ce qui n'est pas logique). Ensuite comment gérer le cas d'un objet parent dont le constructeur contiendrait des paramètres ? En utilisant cette méthode, il est impossible de résoudre ce cas.

La manière correcte d'écrire la fonction Object.create est :

function create(Child, Parent) {
  var Obj = function() { };
  Obj.prototype = Parent.prototype;

  Child.prototype = new Obj();
  Child.prototype.constructor = Child;
}

De cette façon on écrit un héritage tout en conservant nos constructeurs intacts. Cela passe par la création d'un objet intermédiaire n'ayant pas de constructeur, auquel nous connectons le prototype de notre objet parent. Nous utilisons cet objet intermédiaire dans le prototype de notre objet parent auquel nous n'oublions pas rattaché le constructeur de l'objet initial.