Héritage en Javascript

Je reçois un bogue étrange lorsque je met en œuvre l'héritage en version JavaScript en utilisant des prototypes. Je me demande si quelqu'un peut expliquer cela. Dans le code suivant, j'essaie de dériver une classe enfant d'une classe parent:

parent_class=function(byref) { if( !parent_class.prototype._vtbl ) { parent_class.prototype.parent_func= function(o) { return alert("parent_func"); } parent_class.prototype._vtbl = true; } } child=function(byref) { parent_class.call(this,byref); if( !child.prototype._vtbl ) { child.prototype = new parent_class; child.prototype.child_func = parent_class.prototype.parent_func; child.prototype._vtbl = true; } } function dotest() { var pub = new child; alert( pub.child_func ); var pub2 = new child; alert( pub2.child_func ); } dotest(); 

Lorsque vous exécutez le test dans un navigateur (Firefox ou IE), vous obtenez deux alertes. Le premier indique que pub.child_func est indéfini, le second indique que pub.child_func est une fonction valide et parent_class.parent_func. Pourquoi vois-tu ce comportement? Est-ce un bug?

Ordre d'exécution en javascript d'une telle construction:

 function SomeClass () { body(); } var x = new SomeClass(); 

est-ce:

  1. Un nouvel objet qui hérite de SomeClass.prototype est créé (le prototype de l'objet est choisi ici, avant que le code du constructeur ne soit exécuté)
  2. body(); Est exécuté
  3. L'objet créé est attribué à x

Ce que vous pouvez faire dans votre exemple est l'utilisation .__proto__ , même si vous ne devriez vraiment pas:

 child = function (byref) { parent_class.call(this, byref); if (!child.prototype._vtbl) { child.prototype = new parent_class; child.prototype.child_func = parent_class.prototype.parent_func; child.prototype._vtbl = true; } this.__proto__ = child.prototype; } 

Ce que vous devez vraiment faire, c'est ceci:

 child = function (byref) { parent_class.call(this, byref); } child.prototype = Object.create(parent_class.prototype); child.prototype.child_func = parent_class.prototype.parent_func; child.prototype._vtbl = true; 

Une façon plus simple de faire l'héritage JavaScript pourrait être le modèle d'usine:

 function Animal(name) { return { run: function() { alert(name + " is running!") } } } var animal = Animal("fox"); animal.run(); function Rabbit(name) { var rabbit = Animal(name); rabbit.bounce = function() { this.run(); console.log(name + " bounces"); } return rabbit; } var rabbit = Rabbit("rabbit"); rabbit.bounce(); 

Source: http://javascript.info/tutorial/factory-constructor-pattern

Réponse courte : Non, ce n'est pas une erreur de navigateur, c'est un comportement attendu.

Réponse détaillée : lorsqu'une fonction constructeur est appelée avec une new , la référence à son prototype est copiée dans __proto__ des objets. Plus tard, cette propriété est utilisée pour les recherches prototypes pour cet objet.
Votre code est vraiment étrange du point de vue du développeur javascript, lorsque vous modifiez un prototype de constructeur lors de l'exécution des appels du constructeur. Cependant, cela fonctionne. Parce que, après var parent = new parent_class(); Le suivant est le parent.__proto__ === parent_class.prototype vrai parent.__proto__ === parent_class.prototype . C'est la même référence. Ainsi, l'ajout de propriétés à parent_class.prototype est automatiquement sauvegardé dans parent objet parent via une recherche prototypique. Malheureusement, je ne peux pas encore publier de commentaires, alors je dois faire référence à ma réponse, @ RyszardFiński, ce n'est pas une déclaration correcte selon laquelle le prototype est défini avant l'appel du contructeur et ne peut être modifié ultérieurement. C'est le même objet et, à moins que vous ne modifiez les modifications de référence, vous serez immédiatement réfléchi pour tous les objets instanciés

Cependant, dans child code child dans les références des ruines OP, lorsque child.prototype est attribué à un nouvel objet.

child.prototype = new parent_class;

child.prototype commence à pointer vers une nouvelle instance de parent_class (# 1). Les références d'instance ressemblent ci-dessous

 pub.__proto__ === child.prototype pub2.__proto__ === parentInstance1 child.prototype === parentInstance2 

Si vous supprimez la ligne de code où child.prototype est assigné, tout commencera à fonctionner comme vous l'attendiez

 pub.__proto__ === child.prototype pub2.__proto__ === child.prototype child.prototype === child.prototype child.prototype has properties _vtbl and child_func