flanker (./2839) :
Certes, je comprends ça… mais avec le JS, il y a une limite : les modules tiers ne peuvent pas être aussi performants que la bibliothèque standard (qui peut être compilée). On a donc tout intérêt à avoir une bibliothèque standard performante et complète, ou au moins avoir les structures de base (et je pense qu'une table de hash en fait partie).
Accessoirement, comme tu dis, on peut détacher la bibliothèque standard du langage (comme Qt et C++), mais il en faut au moins une de complète. Avec JS, il y en a plein d'incomplètes
Pour les usages "page web" la bibliothèque telle que définie par le w3c est déjà pas mal. Tu citais par exemple jQuery, normalement il n'y a plus besoin de s'en servir depuis que
document.querySelector est disponible partout (d'ailleurs c'est en partie pour ça que la lib est en train de mourir doucement). Pour les usages serveur cf. la réponse de robinHood ; bien sûr c'est un ensemble totalement différent de fonctions puisque c'est un usage qui n'a rien à voir. Après ça renvoie à la question "est-ce que le JS est adapté pour ce cas", mais c'est une question très différente de "est-ce qu'il s'agit d'un bon langage".
flanker (./2839) :
Et voilà, on retrouve une habitude de JS : ça ressemble à une table de hash, ça a le goût d'une table de hash, ça a l'odeur d'une table de hash, mais ce n'est pas une table de hash.
Mais justement : à aucun moment on ne t'a prétendu qu'il s'agissait de près ou de loin d'une table de hash, c'est simplement toi qui a tiré cette conclusion à partir de ta connaissance d'autres langages. J'y reviendrai sur l'héritage prototypal, pour moi c'est une source majeure d'incompréhension : tu essaies de rapprocher une notion JS de quelque chose que tu connais déjà, et comme ça n'est pas exactement identiques tu te plains de toutes les différences. Ce que construit la syntaxe
{a: 1, b: 2} n'est pas une table de hash même si la syntaxe ressemble fortement à ce qui s'appelle une table de hash en Python. C'est même pire que ça : comme je le disais plus haut, si tu voulais vraiment utiliser cette structure comme une table de hash en ajoutant par exemple la notion de "nombre d'éléments" alors tu priverais l'interpréteur de la possibilité de transformer cet objet en une structure fixe, et c'est l'une des opérations de base à effectuer pour qu'un bout de code puisse être traduit en code natif par le JIT.
Je ne comprends vraiment pas l'argument "ça ressemble à une table de hash, donc c'est nul parce que ça n'est pas une vraie table de hash complète", c'est comme si je râlais sur Python parce que
(1, 2, 3, 4) ressemble à une construction de liste dans mon langage préféré mais que
a = (1, 2, 3); a.push(4) ne fonctionne pas et donc que l'implémentation des listes de Python est vraiment pourrie ?
flanker (./2839) :
Ah mais c'est encore pire, je déteste les langages qui ont 50 façons différentes de faire la même chose ; ça rend le code des autres totalement illisible (coucou Scala).
Sur ça je suis complètement d'accord, et à mon avis c'est parce qu'il y a plein de développeurs qui veulent absolument des classes et surtout ne pas comprendre comment fonctionne l'héritage prototypal que les auteurs cèdent et qu'il se retrouve avec des classes en JS, ou tout un tas d'autres doublons
flanker (./2839) :
Mais si tu sais ce qu'apporte cette méthode, je suis preneur
Je peux te donner quelques exemples, mais avant il me semble plus important de répéter mon argument précédent : au lieu d'essayer de résoudre un problème, on essaie de reproduire un moyen. Plutôt que de trouver comment implémenter ce que je veux en utilisant l'héritage prototypal on essaie de l'implémenter avec des classes, mais comme ça n'existe(ait) pas en JS on se retrouve à implémenter un machin hybride qui fait presque comme des classes mais en utilisant les prototypes de JS. Je pense que l'approche "je veux implémenter de cette façon parce que c'est comme ça que je l'aurais fait dans le langage que je connais" n'est pas efficace. Du coup prendre un cas d'école de l'utilisation des classes et essayer de l'écrire en JS est idiot : bien sûr que ça sera moche, mais quel problème essaie-t-on de résoudre ? J'imagine que la réponse n'est pas "je veux une classe Client qui hérite de Person" mais quelque chose d'un peu plus concret, qui peut très certainement s'écrire de 1001 autres façons. C'est pas comme si le C était à court de solutions pour implémenter tout et n'importe quoi, et pourtant il n'y a ni classes ni prototypes.
À l'inverse je peux trouver des cas d'utilisation qui sont favorables à l'héritage par prototype. Mettons par exemple que j'écrive un programme dans lequel j'ai fréquemment besoin d'obtenir l'opposé de chaque élément d'un tableau, je pourrais avoir envie d'une fonction "negate" disponible facilement (bouh, elle n'est pas disponible de base, quelle bibliothèque standard ridicule !). Une solution simple à ça serait de l'ajouter directement sur l'objet
Array :
Array.prototype.negate = function ()
{
return this.map(i => -i);
};
Et hop, à partir de maintenant je peux faire
x = [1, 2, 3]; y = x.negate(); puisque je viens de rendre ma nouvelle fonction sur n'importe quel tableau. Encore mieux : si la méthode
negate devient un jour standard, je pourrai supprimer mon assignation perso et le reste de mon code continuera à fonctionner sans aucun changement, en tapant sur l'implémentation par défaut au lieu de la mienne.
Plus généralement je viens d'étendre la bibliothèque standard, ce qui est une fonctionnalité que pas mal de langages ont essayé de proposer (C# avec les méthodes d'extension, Python avec la méthode magique "__init__" au lieu de constructeurs, etc.). Ça n'est qu'un exemple parmi d'autres, mais ça montre qu'il y a des cas où ce mode d'héritage peut être intéressant, à condition de ne pas chercher à l'évaluer sur les exemples qui illustrent traditionnellement le fonctionnement de l'héritage de classe.