Pour des informations plus générales sur l'héritage et les prototypes dans JavaScript, il est conseillé de lire la page Héritage et chaîne de prototypes.
L'héritage a toujours été présent dans JavaScript. Les exemples de cette page utilisent des méthodes qui ont été introduites avec ECMAScript 5. Les pages décrivant ces méthodes vous permettront de savoir si elles peuvent être émulées ou non (pour les anciennes versions notamment).
Exemple
B
hérite de A
:
function A(a){ this.varA = a; } A.prototype = { faireQuelqueChose : function(){ // ... } } function B(a, b){ A.call(this, a); this.varB = b; } B.prototype = Object.create(A.prototype, { varB : { value: null, enumerable: true, configurable: true, writable: true }, faireQuelqueChose : { value: function(){ // surcharge A.prototype.faireQuelqueChose.apply(this, arguments); // call super // ... }, enumerable: true, configurable: true, writable: true } }); var b = new B(); b.faireQuelqueChose();
Ce qui est à retenir ici :
- Les types sont définis dans
.prototype
- On utiliser
Object.create()
pour l'héritage
La propriété prototype
et la méthode Object.getPrototypeOf
JavaScript peut paraître déroutant, relativement à Java ou C++ car il y a une gestion dynamique, à l'exécution et qu'il n'y a pas de classe. Tous les objets sont des instances.
On voit dans l'exemple précédent que la fonction A
possède une propriété spéciale appelée prototype
. Cette propriété spéciale est liée à l'utilisation de l'opérateur new
. Une référence à l'objet prototype est copié vers la propriété interne [[Prototype]]
de la nouvelle instance. Ainsi, si on fait var a1 = new A()
, JavaScript (une fois que l'objet sera créé en mémoire et avant d'exécuter la fonction A()
avec this
lié à l'objet) définira a1.[[Prototype]] = A.prototype
. Quand on accède aux propriétés d'une instance, JavaScript vérifie d'abord que la propriété en question existe ou non pour l'instance même et si ce n'est pas le cas, consulte [[Prototype]]
. Cela signifie que chaque chose définie dans prototype
est partagée avec toutes les instances et qu'on peut changer certains aspects du prototype par la suite, ces changements seront répercutés pour toutes les instances.
Si, dans l'exemple suivant, on fait var a1 = new A(); var a2 = new A();
alors a1.faireQuelqueChose
se référerait à Object.getPrototypeOf(a1).faireQuelqueChose
, qui correspond exactement à A.prototype.faireQuelqueChose
. Autrement dit : Object.getPrototypeOf(a1).
.faireQuelqueChose
== Object.getPrototypeOf(a2).faireQuelqueChose
== A.prototype.faireQuelqueChose
En résumé, le prototype
correspond au type tandis que Object.getPrototypeOf()
permet de décrire une instance.
[[Prototype]]
est exploré récursivement. Cela signifie qu'on cherche a1.faireQuelqueChose
, puis Object.getPrototypeOf(a1).
, puis faireQuelqueChose
Object.getPrototypeOf(Object.getPrototypeOf(a1)).
et ainsi de suite jusqu'à ce que faireQuelqueChose
Object.getPrototypeOf
renvoie la valeur null
.
Quand on appelle :
var o = new Toto();
JavaScript effectue en fait :
var o = new Object(); o.[[Prototype]] = Toto.prototype; o.Toto();
Puis, si on utilise cette instruction
o.unePropriété;
qui vérifie si o
possède une propriété unePropriété
. Si ce n'est pas le cas, JavaScript vérifiera si Object.getPrototypeOf(o).
existe, si ce n'est pas le cas il vérifie unePropriété
Object.getPrototypeOf(Object.getPrototypeOf(o)).
et ainsi de suite.unePropriété