Avantages de l'héritage prototypique par rapport au classique?


271

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.



Réponses:


560

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):

  1. C'est simple.
  2. C'est puissant.
  3. Cela conduit à un code plus petit et moins redondant.
  4. C'est dynamique et donc c'est mieux pour les langages dynamiques.

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:

  1. Le modèle prototypique de l'héritage prototypique.
  2. Le modèle constructeur de l'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):

Et nous le poussions en tant que petit frère à Java, car un langage complémentaire comme Visual Basic était à C ++ dans les familles de langages de Microsoft à l'époque.

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 :

Cette indirection visait à rendre le langage plus familier aux programmeurs de formation classique, mais n'a pas réussi à le faire, comme nous pouvons le voir d'après la très faible opinion que les programmeurs Java ont de JavaScript. Le modèle de constructeur de JavaScript n'a pas séduit la foule classique. Il a également obscurci la véritable nature prototypique de JavaScript. En conséquence, il y a très peu de programmeurs qui savent utiliser efficacement le langage.

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:

  1. Créez un tout nouvel objet.
  2. Clonez un objet existant et étendez-le.

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:

var circle = {
    radius: 5
};

Nous pouvons calculer l'aire et la circonférence du cercle à partir de son rayon:

circle.area = function () {
    var radius = this.radius;
    return Math.PI * radius * radius;
};

circle.circumference = function () {
    return 2 * Math.PI * this.radius;
};

Maintenant, je veux créer un autre cercle de rayon 10. Une façon de procéder serait:

var circle2 = {
    radius: 10,
    area: circle.area,
    circumference: circle.circumference
};

Cependant, JavaScript offre un meilleur moyen - la délégation . La Object.createfonction est utilisée pour ce faire:

var circle2 = Object.create(circle);
circle2.radius = 10;

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 circleet lui attribuer manuellement un rayon". Eh bien la solution est d'utiliser une fonction pour faire le gros du travail pour vous:

function createCircle(radius) {
    var newCircle = Object.create(circle);
    newCircle.radius = radius;
    return newCircle;
}

var circle2 = createCircle(10);

En fait, vous pouvez combiner tout cela en un seul objet littéral comme suit:

var circle = {
    radius: 5,
    create: function (radius) {
        var circle = Object.create(this);
        circle.radius = radius;
        return circle;
    },
    area: function () {
        var radius = this.radius;
        return Math.PI * radius * radius;
    },
    circumference: function () {
        return 2 * Math.PI * this.radius;
    }
};

var circle2 = circle.create(10);

Héritage prototypique en JavaScript

Si vous remarquez dans le programme ci-dessus que la createfonction crée un clone de circle, lui attribue un nouveau radiuset le renvoie ensuite. C'est exactement ce que fait un constructeur en JavaScript:

function Circle(radius) {
    this.radius = radius;
}

Circle.prototype.area = function () {
    var radius = this.radius;
    return Math.PI * radius * radius;
};

Circle.prototype.circumference = function () {         
    return 2 * Math.PI * this.radius;
};

var circle = new Circle(5);
var circle2 = new Circle(10);

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 newmot-clé lie le thispointeur à l'intérieur du constructeur à un clone de celui prototypedu 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:

À mon avis, le principal avantage de l'héritage prototypique est sa simplicité.

Voyons ce que nous venons de faire. Nous avons créé un objet circlequi avait un rayon de 5. Ensuite, nous l'avons cloné et avons donné au clone un rayon de 10.

Par conséquent, nous n'avons besoin que de deux choses pour faire fonctionner l'héritage prototypique:

  1. Un moyen de créer un nouvel objet (par exemple des littéraux d'objet).
  2. Une façon d'étendre un objet existant (par exemple Object.create).

En revanche, l'héritage classique est beaucoup plus compliqué. En héritage classique, vous avez:

  1. Des classes.
  2. Objet.
  3. Interfaces.
  4. Classes abstraites.
  5. Classes finales.
  6. Classes de base virtuelles.
  7. Constructeurs.
  8. Destructeurs.

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 ":

Les métadonnées sont tout type de description ou de modèle d'autre chose. Les commentaires dans votre code ne sont qu'une description en langage naturel du calcul. Ce qui fait des métadonnées de métadonnées, c'est qu'elles ne sont pas strictement nécessaires. Si j'ai un chien avec des documents généalogiques et que je perds les documents, j'ai toujours un chien parfaitement valide.

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é.

Eh bien, nous savons également que les types statiques ne sont que des métadonnées. Il s'agit d'un type de commentaire spécialisé destiné à deux types de lecteurs: les programmeurs et les compilateurs. Les types statiques racontent une histoire sur le calcul, vraisemblablement pour aider les deux groupes de lecteurs à comprendre l'intention du programme. Mais les types statiques peuvent être supprimés lors de l'exécution, car au final, ce ne sont que des commentaires stylisés. Ils sont comme de la paperasse généalogique: cela pourrait rendre un certain type de personnalité peu sûr plus heureux avec leur chien, mais le chien ne s'en soucie certainement pas.

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 NullPointerExceptions 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:

  1. Variables privées.
  2. Héritage multiple.

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 :

  1. Délégation ou héritage différentiel
  2. Clonage ou héritage concaténatif

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, _.extendfait juste cela.

Bien sûr, de nombreux programmeurs ne considèrent pas cela comme un véritable héritage instanceofet isPrototypeOfdisent 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:

function copyOf(object, prototype) {
    var prototypes = object.prototypes;
    var prototypeOf = Object.isPrototypeOf;
    return prototypes.indexOf(prototype) >= 0 ||
        prototypes.some(prototypeOf, prototype);
}

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 :

Vous devez aimer le niveau de bureaucratie de Java "veuillez le signer en quatre exemplaires" ici.

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.


33
Bien que je comprenne d'où vous venez et que je conviens que l'héritage prototypique est très utile, je pense qu'en faisant l'hypothèse "l'héritage prototypique est meilleur que l'héritage classique", vous êtes déjà destiné à échouer. Pour vous donner une certaine perspective, ma bibliothèque jTypes est une bibliothèque d'héritage classique pour JavaScript. Donc, étant un gars qui a pris le temps de le faire, je resterai ici et dirai que l'héritage prototypique est génial et très utile. Mais ce n'est qu'un outil parmi tant d'autres qu'un programmeur possède. L'héritage prototypique présente également de nombreux inconvénients.
redline

7
Je suis entièrement d'accord avec ce que vous avez dit. Je pense que trop de programmeurs rejettent JavaScript pour son manque d'héritage classique, ou le dénoncent comme un langage simple et stupide. C'est en fait un concept extrêmement puissant, je suis d'accord, et de nombreux programmeurs devraient l'accepter et l'apprendre. Cela étant dit, je pense également qu'il existe un nombre important de développeurs en JavaScript qui s'opposent à toute forme d'héritage classique tous ensemble en JavaScript, alors qu'ils n'ont vraiment aucune base pour leurs arguments. Les deux sont tout aussi puissants en eux-mêmes et tout aussi utiles.
redline

9
Eh bien, c'est votre opinion, mais je continuerai d'être en désaccord, et je pense que la popularité croissante de choses telles que CoffeeScript et TypeScript montre qu'il existe une grande communauté de développeurs qui souhaitent utiliser cette fonctionnalité le cas échéant. Comme vous l'avez dit, ES6 ajoute du sucre syntaxique, mais n'offre toujours pas l'étendue des jTypes. En passant, je ne suis pas le seul responsable de votre downvote. Bien que je sois en désaccord avec vous, je ne pense pas que cela constitue une mauvaise réponse. Vous étiez très minutieux.
redline

25
Vous utilisez souvent Word Clone , ce qui est tout simplement faux. Object.createcrée un nouvel objet avec le prototype spécifié. Votre choix de mots donne l'impression que le prototype est cloné.
Pavel Horal

7
@Aadit: il n'est vraiment pas nécessaire d'être aussi défensif. Votre réponse est très détaillée et mérite des votes. Je ne suggérais pas que "lié" devrait être un remplacement direct de "clone", mais qu'il décrit de manière plus appropriée la connexion entre un objet et le prototype dont il hérite, que vous affirmiez votre propre définition du terme "clone" " ou pas. Changez-le ou ne le changez pas, c'est entièrement votre choix.
Andy E

42

Permettez-moi de répondre à la question en ligne.

L'héritage des prototypes a les vertus suivantes:

  1. Il est mieux adapté aux langages dynamiques car l'héritage est aussi dynamique que l'environnement dans lequel il se trouve. (L'applicabilité à JavaScript devrait être évidente ici.) Cela vous permet de faire les choses rapidement à la volée comme la personnalisation de classes sans énormes quantités de code d'infrastructure .
  2. Il est plus facile d'implémenter un schéma d'objet de prototypage que les schémas classiques de dichotomie classe / objet.
  3. Il élimine le besoin de bords tranchants complexes autour du modèle d'objet comme les "métaclasses" (je n'ai jamais métaclasse que j'aimais ... désolé!) Ou les "valeurs propres" ou similaires.

Il présente cependant les inconvénients suivants:

  1. La vérification de type d'un langage prototype n'est pas impossible, mais c'est très, très difficile. La plupart des «vérifications de type» des langages prototypiques sont des vérifications de style «typage du canard» à l'exécution. Cela ne convient pas à tous les environnements.
  2. Il est également difficile de faire des choses comme l'optimisation de la répartition des méthodes par analyse statique (ou, souvent, même dynamique!). Il peut (je souligne: peut ) être très inefficace très facilement.
  3. De même, la création d'objets peut être (et est généralement) beaucoup plus lente dans un langage de prototypage que dans un schéma de dichotomie classe / objet plus conventionnel.

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.


1
Hé, regardez, une réponse concise qui ne fanboy pas. J'aimerais vraiment que ce soit la meilleure réponse à la question.
siliconrockstar

Nous avons aujourd'hui des compilateurs dynamiques juste à temps qui peuvent compiler le code pendant que le code s'exécute en créant différents morceaux de code pour chaque section. JavaScript est en fait plus rapide que Ruby ou Python qui utilisent des classes classiques à cause de cela même si vous utilisez des prototypes car beaucoup de travail a été fait pour l'optimiser.
aoeu256

28

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.createméthode, qui vous permet de produire une nouvelle instance d'objet qui hérite d'une autre de manière très simple:

var obj = Object.create(baseInstance);

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 ...


11
"votre code est plus petit, moins redondant ...", pourquoi? J'ai jeté un œil au lien wikipedia pour "héritage différentiel" et il n'y a rien qui supporte ces assertions. Pourquoi l'héritage classique entraînerait-il un code plus grand et plus redondant?
Noel Abrahams

4
Exactement, je suis d'accord avec Noel. L'héritage prototypique est simplement une façon de faire un travail, mais cela ne fait pas de la bonne façon. Différents outils fonctionneront de différentes manières pour différents travaux. L'héritage prototypique a sa place. C'est un concept extrêmement puissant et simple. Cela étant dit, le manque de prise en charge de la véritable encapsulation et du polymorphisme place JavaScript dans une position très défavorable. Ces méthodologies existent depuis bien plus longtemps que JavaScript, et elles sont solides dans leurs principes. Donc, penser que le prototype est "meilleur" n'est tout simplement pas la bonne mentalité.
redline

1
Vous pouvez simuler l'héritage basé sur une classe à l'aide de l'héritage basé sur un prototype, mais pas l'inverse. Cela pourrait être un bon argument. Je vois aussi l'encapsulation plus comme une convention que comme une fonction de langage (généralement, vous pouvez rompre l'encapsulation par réflexion). Concernant le polymorphisme - tout ce que vous gagnez n'est pas d'avoir à écrire des conditions "si" simples lors de la vérification des arguments de la méthode (et un peu de vitesse si la méthode cible est résolue pendant la compilation). Aucun réel inconvénient JavaScript ici.
Pavel Horal

Les prototypes sont impressionnants, OMI. Je pense à créer un langage fonctionnel comme Haskell ... mais au lieu de créer des abstractions je baserai tout sur des prototypes. Au lieu de généraliser la somme, et factorielle à "plier", vous devriez utiliser le prototype de la fonction somme et remplacer le + par * et 0 par 1 pour fabriquer le produit. J'expliquerai les "Monades" comme des prototypes qui remplacent "puis" des promesses / rappels avec flatMap étant synonyme de "alors". Je pense que les prototypes peuvent aider à apporter une programmation fonctionnelle aux masses.
aoeu256

11

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

var single = { status: "Single" },
    princeWilliam = Object.create(single),
    cliffRichard = Object.create(single);

console.log(Object.keys(princeWilliam).length); // 0
console.log(Object.keys(cliffRichard).length); // 0

// Marriage event occurs
princeWilliam.status = "Married";

console.log(Object.keys(princeWilliam).length); // 1 (New instance property)
console.log(Object.keys(cliffRichard).length); // 0 (Still refers to prototype)

Classique avec des méthodes d'instance (inefficace car chaque instance stocke sa propre propriété)

function Single() {
    this.status = "Single";
}

var princeWilliam = new Single(),
    cliffRichard = new Single();

console.log(Object.keys(princeWilliam).length); // 1
console.log(Object.keys(cliffRichard).length); // 1

Classique efficace

function Single() {
}

Single.prototype.status = "Single";

var princeWilliam = new Single(),
    cliffRichard = new Single();

princeWilliam.status = "Married";

console.log(Object.keys(princeWilliam).length); // 1
console.log(Object.keys(cliffRichard).length); // 0
console.log(cliffRichard.status); // "Single"

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.


2
En regardant d'autres réponses et ressources sur ce sujet, votre réponse semble indiquer: «L'héritage prototypique est un sous-ensemble du sucre syntaxique ajouté à JavaScript pour permettre l'apparition de l'héritage classique». L'OP semble poser des questions sur les avantages de l'héritage prototypique dans JS par rapport à l'héritage classique dans d'autres langages plutôt que de comparer les techniques d'instanciation dans JavaScript.
A Fader Darkly

2

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


20
Je pense qu'il vaut mieux résumer le contenu des liens plutôt que de coller le lien (quelque chose que je faisais moi-même), sauf si c'est un autre lien SO. En effet, les liens / sites tombent en panne et vous perdez la réponse à la question, ce qui affecte potentiellement les résultats de la recherche.
James Westgate

Le 1er lien ne répond pas à la question de savoir pourquoi l' héritage prototypique? Il le décrit simplement.
viebel
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.