J'ai donc finalement arrêté de me traîner les pieds pendant toutes ces années et j'ai décidé d'apprendre "correctement" JavaScript. L'un des éléments les plus frappants de la conception des langages est l'implémentation de l'héritage. Ayant de l'expérience en Ruby, j'étais vraiment heureux de voir des fermetures et des typages dynamiques; mais pour la vie de moi, je ne peux pas comprendre quels avantages doivent être tirés des instances d'objets utilisant d'autres instances pour l'héritage.
271
Réponses:
Je sais que cette réponse a 3 ans de retard mais je pense vraiment que les réponses actuelles ne fournissent pas suffisamment d'informations sur la façon dont l'héritage prototypique est meilleur que l'héritage classique .
Voyons d'abord les arguments les plus courants des programmeurs JavaScript pour défendre l'héritage prototypique (je prends ces arguments du pool de réponses actuel):
Maintenant, ces arguments sont tous valables, mais personne n'a pris la peine d'expliquer pourquoi. C'est comme dire à un enfant qu'il est important d'étudier les mathématiques. Bien sûr que oui, mais l'enfant ne s'en soucie certainement pas; et vous ne pouvez pas faire un enfant comme Maths en disant que c'est important.
Je pense que le problème de l'héritage prototypique est qu'il est expliqué du point de vue de JavaScript. J'adore JavaScript, mais l'héritage prototypique en JavaScript est faux. Contrairement à l'héritage classique, il existe deux modèles d'héritage prototypique:
Malheureusement, JavaScript utilise le modèle constructeur de l'héritage prototypique. En effet, lorsque JavaScript a été créé, Brendan Eich (le créateur de JS) voulait qu'il ressemble à Java (qui a un héritage classique):
C'est mauvais parce que lorsque les gens utilisent des constructeurs en JavaScript, ils pensent aux constructeurs héritant d'autres constructeurs. C'est faux. Dans l'héritage prototypique, les objets héritent d'autres objets. Les constructeurs n'entrent jamais en scène. C'est ce qui déroute la plupart des gens.
Les gens de langages comme Java, qui a un héritage classique, deviennent encore plus confus parce que bien que les constructeurs ressemblent à des classes, ils ne se comportent pas comme des classes. Comme l'a déclaré Douglas Crockford :
Voilà. Directement de la bouche du cheval.
Véritable héritage prototypique
L'héritage prototypique concerne les objets. Les objets héritent des propriétés des autres objets. C'est tout ce qu'on peut en dire. Il existe deux façons de créer des objets à l'aide de l'héritage prototypique:
Remarque: JavaScript propose deux façons de cloner un objet: la délégation et la concaténation . Dorénavant, j'utiliserai le mot "clone" pour désigner exclusivement l'héritage via délégation, et le mot "copie" pour désigner exclusivement l'héritage via concaténation.
Assez parlé. Voyons quelques exemples. Disons que j'ai un cercle de rayon
5
:Nous pouvons calculer l'aire et la circonférence du cercle à partir de son rayon:
Maintenant, je veux créer un autre cercle de rayon
10
. Une façon de procéder serait:Cependant, JavaScript offre un meilleur moyen - la délégation . La
Object.create
fonction est utilisée pour ce faire:C'est tout. Vous venez de faire l'héritage prototypique en JavaScript. N'était-ce pas aussi simple? Vous prenez un objet, le clonez, changez tout ce dont vous avez besoin, et hé hop - vous vous êtes procuré un tout nouvel objet.
Maintenant, vous pourriez demander: "Comment est-ce simple? Chaque fois que je veux créer un nouveau cercle, je dois cloner
circle
et lui attribuer manuellement un rayon". Eh bien la solution est d'utiliser une fonction pour faire le gros du travail pour vous:En fait, vous pouvez combiner tout cela en un seul objet littéral comme suit:
Héritage prototypique en JavaScript
Si vous remarquez dans le programme ci-dessus que la
create
fonction crée un clone decircle
, lui attribue un nouveauradius
et le renvoie ensuite. C'est exactement ce que fait un constructeur en JavaScript:Le modèle constructeur en JavaScript est le modèle prototype inversé. Au lieu de créer un objet, vous créez un constructeur. Le
new
mot-clé lie lethis
pointeur à l'intérieur du constructeur à un clone de celuiprototype
du constructeur.Cela vous semble confus? C'est parce que le modèle de constructeur en JavaScript complique inutilement les choses. C'est ce que la plupart des programmeurs trouvent difficile à comprendre.
Au lieu de penser à des objets héritant d'autres objets, ils pensent aux constructeurs héritant d'autres constructeurs et deviennent alors complètement confus.
Il y a tout un tas d'autres raisons pour lesquelles le modèle de constructeur en JavaScript doit être évité. Vous pouvez en lire plus dans mon article de blog ici: Constructeurs vs prototypes
Quels sont donc les avantages de l'héritage prototypique par rapport à l'héritage classique? Reprenons les arguments les plus courants et expliquons pourquoi .
1. L'héritage prototypique est simple
CMS déclare dans sa réponse:
Voyons ce que nous venons de faire. Nous avons créé un objet
circle
qui avait un rayon de5
. Ensuite, nous l'avons cloné et avons donné au clone un rayon de10
.Par conséquent, nous n'avons besoin que de deux choses pour faire fonctionner l'héritage prototypique:
Object.create
).En revanche, l'héritage classique est beaucoup plus compliqué. En héritage classique, vous avez:
Vous avez eu l'idée. Le fait est que l'héritage prototypique est plus facile à comprendre, à mettre en œuvre et à raisonner.
Comme Steve Yegge le dit dans son blog classique " Portrait of a N00b ":
Dans le même sens, les classes ne sont que des métadonnées. Les classes ne sont pas strictement requises pour l'héritage. Cependant, certaines personnes (généralement n00bs) trouvent les classes plus confortables avec lesquelles travailler. Cela leur donne un faux sentiment de sécurité.
Comme je l'ai dit plus tôt, les cours donnent aux gens un faux sentiment de sécurité. Par exemple, vous obtenez trop de
NullPointerException
s en Java même lorsque votre code est parfaitement lisible. Je trouve que l'héritage classique gêne généralement la programmation, mais c'est peut-être juste Java. Python possède un incroyable système d'héritage classique.2. L'héritage prototypique est puissant
La plupart des programmeurs issus d'un milieu classique soutiennent que l'héritage classique est plus puissant que l'héritage prototypique car il a:
Cette affirmation est fausse. Nous savons déjà que JavaScript prend en charge les variables privées via des fermetures , mais qu'en est-il de l'héritage multiple? Les objets en JavaScript n'ont qu'un seul prototype.
La vérité est que l'héritage prototypique prend en charge l'héritage de plusieurs prototypes. L'héritage prototypique signifie simplement un objet héritant d'un autre objet. Il existe en fait deux façons d'implémenter l'héritage prototypique :
Oui, JavaScript permet uniquement aux objets de se déléguer à un autre objet. Cependant, il vous permet de copier les propriétés d'un nombre arbitraire d'objets. Par exemple,
_.extend
fait juste cela.Bien sûr, de nombreux programmeurs ne considèrent pas cela comme un véritable héritage
instanceof
etisPrototypeOf
disent le contraire. Cependant, cela peut être facilement résolu en stockant un tableau de prototypes sur chaque objet qui hérite d'un prototype via la concaténation:L'héritage prototypique est donc tout aussi puissant que l'héritage classique. En fait, il est beaucoup plus puissant que l'héritage classique, car dans l'héritage prototypique, vous pouvez choisir manuellement les propriétés à copier et les propriétés à omettre des différents prototypes.
Dans l'héritage classique, il est impossible (ou du moins très difficile) de choisir les propriétés dont vous souhaitez hériter. Ils utilisent des classes de base virtuelles et des interfaces pour résoudre le problème du diamant .
En JavaScript, cependant, vous n'aurez probablement jamais entendu parler du problème du diamant, car vous pouvez contrôler exactement quelles propriétés vous souhaitez hériter et de quels prototypes.
3. L'héritage prototypique est moins redondant
Ce point est un peu plus difficile à expliquer car l'héritage classique ne conduit pas nécessairement à un code plus redondant. En fait, l'héritage, qu'il soit classique ou prototypique, est utilisé pour réduire la redondance dans le code.
Un argument pourrait être que la plupart des langages de programmation avec héritage classique sont typés statiquement et nécessitent que l'utilisateur déclare explicitement les types (contrairement à Haskell qui a un typage statique implicite). Par conséquent, cela conduit à un code plus détaillé.
Java est connu pour ce comportement. Je me souviens clairement que Bob Nystrom avait mentionné l'anecdote suivante dans son article de blog sur Pratt Parsers :
Encore une fois, je pense que c'est uniquement parce que Java est nul.
Un argument valable est que toutes les langues qui ont un héritage classique ne prennent pas en charge l'héritage multiple. Encore une fois, Java me vient à l'esprit. Oui, Java a des interfaces, mais ce n'est pas suffisant. Parfois, vous avez vraiment besoin d'un héritage multiple.
Étant donné que l'héritage prototypique permet l'héritage multiple, le code qui requiert l'héritage multiple est moins redondant s'il est écrit en utilisant l'héritage prototypique plutôt que dans un langage qui a l'héritage classique mais pas d'héritage multiple.
4. L'héritage prototypique est dynamique
L'un des avantages les plus importants de l'héritage prototypique est que vous pouvez ajouter de nouvelles propriétés aux prototypes après leur création. Cela vous permet d'ajouter de nouvelles méthodes à un prototype qui seront automatiquement mises à la disposition de tous les objets qui délègueront à ce prototype.
Cela n'est pas possible dans l'héritage classique car une fois qu'une classe est créée, vous ne pouvez pas la modifier au moment de l'exécution. C'est probablement le plus grand avantage de l'héritage prototypique par rapport à l'héritage classique, et il aurait dû être au sommet. Cependant j'aime garder le meilleur pour la fin.
Conclusion
L'héritage prototypique est important. Il est important d'éduquer les programmeurs JavaScript sur les raisons d'abandonner le modèle constructeur d'héritage prototypique au profit du modèle prototypique d'héritage prototypique.
Nous devons commencer à enseigner correctement JavaScript et cela signifie montrer aux nouveaux programmeurs comment écrire du code en utilisant le modèle prototypique au lieu du modèle constructeur.
Non seulement il sera plus facile d'expliquer l'héritage prototypique à l'aide du modèle prototypique, mais cela fera également de meilleurs programmeurs.
Si vous avez aimé cette réponse, vous devriez également lire mon article de blog sur " Pourquoi l'héritage prototypique est important ". Croyez-moi, vous ne serez pas déçu.
la source
Object.create
crée un nouvel objet avec le prototype spécifié. Votre choix de mots donne l'impression que le prototype est cloné.Permettez-moi de répondre à la question en ligne.
L'héritage des prototypes a les vertus suivantes:
Il présente cependant les inconvénients suivants:
Je pense que vous pouvez lire entre les lignes ci-dessus et trouver les avantages et les inconvénients correspondants des schémas de classe / objet traditionnels. Il y a, bien sûr, plus dans chaque domaine, donc je laisse le reste à d'autres personnes qui répondront.
la source
OMI, le principal avantage de l'héritage prototypique est sa simplicité.
La nature prototypique de la langue peut dérouter les gens qui ont une formation classique , mais il s'avère qu'en réalité c'est un concept vraiment simple et puissant, l' héritage différentiel .
Vous n'avez pas besoin de faire de classification , votre code est plus petit, moins redondant, les objets héritent d'autres objets plus généraux.
Si vous pensez de manière prototypique, vous remarquerez bientôt que vous n'avez pas besoin de cours ...
L'héritage prototypique sera beaucoup plus populaire dans un avenir proche, la spécification ECMAScript 5e édition a introduit la
Object.create
méthode, qui vous permet de produire une nouvelle instance d'objet qui hérite d'une autre de manière très simple:Cette nouvelle version de la norme est mise en œuvre par tous les fournisseurs de navigateurs, et je pense que nous commencerons à voir un héritage prototypique plus pur ...
la source
Il n'y a vraiment pas beaucoup de choix entre les deux méthodes. L'idée de base à saisir est que lorsque le moteur JavaScript reçoit une propriété d'un objet à lire, il vérifie d'abord l'instance et si cette propriété est manquante, il vérifie la chaîne du prototype. Voici un exemple qui montre la différence entre le prototype et le classique:
Prototypal
Classique avec des méthodes d'instance (inefficace car chaque instance stocke sa propre propriété)
Classique efficace
Comme vous pouvez le voir, puisqu'il est possible de manipuler le prototype de "classes" déclarées dans le style classique, il n'y a vraiment aucun avantage à utiliser l'héritage prototypique. Il s'agit d'un sous-ensemble de la méthode classique.
la source
Développement Web: héritage prototypique vs héritage classique
http://chamnapchhorn.blogspot.com/2009/05/prototypal-inheritance-vs-classical.html
Héritage prototypique Vs classique - Débordement de pile
Héritage prototypique Vs classique
la source