Copie de prototype vs Object.create () vs new

J'utilise les héritages et j'ai remarqué qu'il y a trois façons d'obtenir le même résultat. Quelle est la différence?

function Animal(){ } Animal.prototype.doThat = function() { document.write("Doing that"); } function Bird(){ } // This makes doThat() visible Bird.prototype = Object.create(Animal.prototype); // Solution 1 // You can also do: // Bird.prototype = new Animal(); // Solution 2 // Or: // Bird.prototype = Animal.prototype; // Solution 3 var myVar = new Bird(); myVar.doThat(); 

Comme vous pouvez le voir, j'ai proposé trois solutions. Chacun d'entre eux fait la méthode doThat () visible.

Si je les formule tous, il y a une erreur.

Si je décompose seulement l'un d'eux, le programme fonctionne.

Alors … quelle est vraiment la différence entre les trois solutions?

Bird.prototype = Animal.prototype; // Solution 3

Étant donné que ce projet Animal.prototype attribué directement à Bird.prototype , toutes les modifications apportées à ce dernier seront également reflétées dans Animal et toutes les autres classes qui en héritent.

Par exemple:

 Bird.prototype.fly = function() { console.log('I can fly.'); } var some_animal = new Animal(); some_animal.fly(); // this will work 

Ce n'est certainement pas ce que vous voulez. Non seulement toutes les méthodes de cette sous-classe sont disponibles pour d'autres sous-classes, mais si vous supprimez les méthodes parent dans les sous-classes, la sous-classe qui a été définie en dernier remplacera les modifications des autres sous-classes.

Dans votre titre de question, vous semblez vous référer à ceci comme "copie prototype". Ceci n'est pas correct car aucune copie n'est créée. Animal.prototype et Bird.prototype se référeront à un même objet.


Bird.prototype = new Animal(); // Solution 2

Cela a été un moyen commun de configurer l'héritage pendant une longue période, mais il présente deux inconvénients majeurs:

  • Si Animal requiert des arguments, qu'est-ce que vous passez? Passer au hasard, les arguments sans signification juste pour rendre l'appel de fonction fonctionnel semble être une mauvaise conception.
  • Animal peuvent avoir des effets secondaires, comme augmenter un compteur d'instance, mais en ce moment, vous n'avez pas vraiment créé une nouvelle instance (ou ne voulez pas), vous vouliez simplement configurer l'héritage.

Bird.prototype = Object.create(Animal.prototype); // Solution 1

C'est comme ça que vous devriez le faire maintenant ( jusqu'à ce qu'une meilleure solution soit disponible ). Tout ce que vous voulez vraiment faire est de brancher le prototype d' Animal dans la chaîne prototype de Bird . Cela évite tous les inconvénients des solutions précédentes.

Pour que cela fonctionne correctement, vous devez également appeler le constructeur Animal dans le constructeur Bird . C'est comme un appel à super dans d'autres langages de programmation:

 function Bird(){ Animal.call(this); } 

Cela garantit que toutes les commandes / modifications apportées à une nouvelle instance Animal sont appliquées à la nouvelle instance Bird .

Il est également recommandé d'attribuer la valeur correcte à la propriété constructor du prototype. Il se réfère généralement à la fonction que le prototype "appartient", mais dans toutes les solutions ci-dessus, Bird.prototype.constructor se référera à Animal . Nous devons donc:

 Bird.prototype.constructor = Bird; 

Cette propriété n'est pas utilisée en interne, donc vous devez le faire uniquement si votre propre code s'appuie sur celui-ci. Cependant, si vous créez une bibliothèque pour être utilisée par d'autres, ils s'attendront probablement à ce que la propriété ait à corriger la valeur.

Vous pouvez soit utiliser la Solution 1 ou la Solution 2 , mais vous ne devriez pas utiliser la Solution 3 .

La raison en est lorsque vous faites Bird.prototype = Animal.prototype; , Chaque changement sur Bird.prototype affectera également Animal.prototype , car ils ont le même objet.

Par exemple, vous attachez une méthode sur Bird.prototype , alors la méthode fonctionnera également sur Animal , ce qui ne sera pas ce que vous voulez.