Héritage en Javascript

Quand j’ai lancé mon projet de refaire une application à la netvibes, je me suis mis à AJAX. Et donc je me suis demandé si on pouvait faire des classes en Javascript. J’ai rapidement été confronté à l’héritage.

Le plus étonnant, dans mes recherches sur l’écriture du Javascript, c’est que j’ai trouvé du code qui ne marche pas. Je n’ai pas poussé mes recherches pour savoir où ça s’appliquait (le javascript, ce n’est pas que sur les navigateurs internet) et je suis tombé simplement sur la documentation de Mozilla. Le Javascript est basé sur les prototypes.

Test 1

Voilà donc mon premier test :

// class MamanOurs
var MamanOurs = function(nom){
   this.nom = nom;
   this.cri = "RAWWWWRR !!!";
};
// Méthode rawr de MamanOurs
MamanOurs.prototype.rawr = function(){
   alert(this.nom + " crie : " + this.cri);
};
 
// class BebeOurs
// notez que pour appeller le constructeur parant, on utilise __proto__.constructor
var BebeOurs = function(nom){
   this.__proto__.constructor(nom);
   this.cri = "roooo ...";
};
// voilà  l'héritage
BebeOurs.prototype = new MamanOurs;
 
// Instanciation
var bouba = new BebeOurs("Bouba");
bouba.rawr();

Bon, c’est pas mal je trouve. Le nom a bien été enregistré et le cri a bien changé.

Test 2

Puis un autre test plus poussé :

var MamanOurs = function(nom){
   this.nom = nom;
   this.cri = "RAWWWWRR !!!";
};
MamanOurs.prototype.rawr = function(){
   alert(this.nom + " crie : " + this.cri);
};
MamanOurs.prototype.faitSaCrotte = function(){
   alert(this.nom + " fait sa crotte");
   this.rawr();
};
var BebeOurs = function(nom){
   this.__proto__.constructor(nom);
   this.cri = "roooo ...";
};
BebeOurs.prototype = new MamanOurs;
// il y a 2 fois __proto__ parce qu'il faut remonter de 2 crans
// on est dans BebeOurs.prototype et non dans BebeOurs comme au dessus dans le constructeur
BebeOurs.prototype.faitSaCrotte = function(){
   alert(this.nom + " va chercher sa maman");
   this.__proto__.__proto__.faitSaCrotte();
};
 
var bouba = new BebeOurs("Bouba");
bouba.faitSaCrotte();

Et là, problème, Bouba va bien chercher sa maman, mais pour faire sa crotte, il a oublié son nom (ne me demandez pas où je vais chercher mon inspiration :) ).

Test 3

Après plusieurs logs, on voit bien que c’est un problème de scope. J’ai donc pensé à un delegate que j’ai découvert en Flash.

var delegate = function(pTarget, pFunction){
   var f = function(){
      return arguments.callee.func.apply(arguments.callee.target, arguments);
   };
   f.target = pTarget;
   f.func = pFunction;
   return f;
};
var MamanOurs = function(nom){
   this.nom = nom;
   this.cri = "RAWWWWRR !!!";
};
MamanOurs.prototype.rawr = function(){
   alert(this.nom + " crie : " + this.cri);
};
MamanOurs.prototype.faitSaCrotte = function(){
   alert(this.nom + " fait sa crotte");
   this.rawr();
};
var BebeOurs = function(nom){
   this.__proto__.constructor(nom);
   this.cri = "roooo ...";
};
BebeOurs.prototype = new MamanOurs;
BebeOurs.prototype.faitSaCrotte = function(){
   alert(this.nom + " va chercher sa maman");
   delegate(this, this.__proto__.__proto__.faitSaCrotte)();
};
 
var bouba = new BebeOurs("Bouba");
bouba.faitSaCrotte();

Et là Bouba n’a pas oublié son nom pour faire sa crotte ! Elle est pas belle la vie ? :)

Les fichiers des 3 tests : test 1, test 2, test 3

Commentaires