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:
SomeClass.prototype
est créé (le prototype de l'objet est choisi ici, avant que le code du constructeur ne soit exécuté) body();
Est exécuté 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