Notez que je fonde tous mes arguments sur des cas d'utilisation réels. Les contre-arguments qui ne peuvent pas être sauvegardés avec un exemple d'utilisation dans des applications réelles, complètes, intéressantes et utiles ne sont pas valides. J'ai vu les petites "démos de langage" que tout le monde a, j'ai vu les articles de blog détaillant comment les prototypes et la frappe dynamique rendent un petit exemple trivial quelques lignes plus court qu'en C #, mais ceux-ci ne sont tout simplement pas pertinents aux problèmes que vous rencontrez pour écrire du vrai
code plutôt que des micro-démos et des jouets. Voici donc mes reproches avec JS:
a) Magie «ceci». C'est ça, sauf quand c'est ça. JavaScript vous pousse à utiliser des fonctions anonymes partout, sauf qu'elles finissent toujours par perdre le contexte approprié pour la variable 'this', donc vous finissez par avoir du code maladroit comme "var _this = this" partout et ensuite en utilisant cela à l'intérieur de vos rappels ou d'autres fonctions. Certains jours, je jure que le nombre de fonctions que j'arrive à écrire et qui n'utilisent pas un «ceci» renommé sont en fait plus petites que le nombre qui le fait.
b) 1 + "1" - 1 = 10. Aussi, "1" + 0 = "10". Oui, cela a en fait causé des bogues pour nos applications, où les données qui devraient être un nombre ont été chargées à partir d'un fichier JSON en tant que chaîne en raison d'un bogue dans une autre application, et le résultat n'était pas bon. Tout notre code de chargement a dû être mis à jour pour ajouter une tonne de conversions de type partout. Quand j'ai besoin que quelque chose soit un nombre, je veux vraiment que ce soit un nombre, pas une chaîne ou un objet ou null ou autre chose. Lua, qui est très similaire à JavaScript à bien des égards, a résolu ce problème en n'étant pas suffisamment retardé pour utiliser le même opérateur pour l'ajout et la concaténation de chaînes.
c) Variables globales par défaut. Donc, même si vous prenez l'argument selon lequel la saisie dynamique est simplement "plus facile" parce que vous n'avez pas à penser aux déclarations de variables, JavaScript jette cet argument par la fenêtre en vous faisant mettre 'var' devant de nouveaux identifiants partout . Et puis il vous visse silencieusement si vous oubliez.
d) Prototypes au lieu de classes. Il existe très peu d'applications JavaScript à grande échelle dans le monde réel qui ne se connectent pas à leur propre système de classe pour contourner l'inutilité inhérente des prototypes dans l'architecture des grandes applications. Ces mêmes applications font un usage minimal des prototypes pour étendre les types JavaScript de base, et uniquement parce que JS était si mal conçu que même les deux types intégrés intéressants qu'il contient manquent de la moitié des fonctionnalités que vous attendez d'eux.
e) Impossibilité de créer des types de valeur de passage. C'est un problème fréquent dans à peu près tous les langages en dehors de C ++ / D, en fait. Pour ceux qui utilisent JavaScript pour écrire des applications WebGL, jetez un œil à toutes les bibliothèques d'algèbre linéaire pour JavaScript. Dans les applications 3D, vous utilisez presque plus souvent des vecteurs que des scalaires. Imaginez que chaque entier de votre application soit passé par référence, de sorte que "a = 1; b = a; b ++" rende a et b égaux à 2. Chaque petit vecteur à trois composants est un objet complet complet. Ils sont passés par référence (la source de près de la moitié des bogues de notre jeu WebGL jusqu'à présent, en fait). Ils existent en grande quantité, sont alloués en tas et récupérés, ce qui met une pression intense sur le GC, ce qui peut entraîner et fait des pauses dans les jeux WebGL même simples, à moins que le développeur ne passe par des cercles ridiculement compliqués pour éviter de créer de nouveaux vecteurs à tous les endroits où il est logique de créer de nouveaux vecteurs. Vous ne pouvez pas avoir de surcharge d'opérateur, vous avez donc des expressions très grandes et laides pour effectuer des opérations de base. L'accès aux composants individuels est lent. Les objets ne sont pas nativement compressés et sont donc incroyablement lents à pousser dans un tampon de vertex, sauf si vous les implémentez en tant qu'instances Float32Array, ce qui confond la merde des optimiseurs de V8 et SpiderMonkey actuellement. Ai-je mentionné qu'ils sont adoptés par référence? L'accès aux composants individuels est lent. Les objets ne sont pas nativement compressés et sont donc incroyablement lents à pousser dans un tampon de vertex, sauf si vous les implémentez en tant qu'instances Float32Array, ce qui confond la merde des optimiseurs de V8 et SpiderMonkey actuellement. Ai-je mentionné qu'ils sont adoptés par référence? L'accès aux composants individuels est lent. Les objets ne sont pas nativement compressés et sont donc incroyablement lents à pousser dans un tampon de vertex, sauf si vous les implémentez en tant qu'instances Float32Array, ce qui confond la merde des optimiseurs de V8 et SpiderMonkey actuellement. Ai-je mentionné qu'ils sont adoptés par référence?
f) Aucune fonctionnalité intégrée n'inclut ni ne nécessite de fonctionnalité. Sérieusement, toujours. Les bibliothèques tierces existent mais presque toutes ont une sorte de bogue ou une autre, dont la moindre n'est pas un problème de mise en cache déroutant dans au moins Chrome, ce qui rend le développement réel pénible.
g) Typage dynamique. Oui, je suis prêt à commencer cet argument. Vous commencez à le remarquer le plus souvent à la seconde où vous arrêtez d'écrire de petites applications Web ou pages Web et commencez à écrire de grandes applications où vous avez réellement des données qui persistent plus longtemps qu'un simple clic de souris ou un cycle de demande / réponse: ajoutez le mauvais type d'objet à un tableau à traiter plus tard et à obtenir un plantage plus tard à partir d'une méthode ou d'un membre manquant dans un bit de code complètement différent de celui où se trouvait l'erreur réelle. Des moments de plaisir. Oui, Java rend le typage statique mauvais. Non, Java / C # / C ++ ne sont pas le seul et unique moyen de faire du typage statique. L'inférence de type, la liaison d'interface implicite, etc. vous offrent tous les avantages «faciles à gérer et peu de frappes» de la frappe dynamique sans tous les bogues. Le deuxième langage Web le plus populaire - ActionScript 3 - est typé statiquement, en fait, bien qu'il soit par ailleurs identique à JS / ECMAScript. En passant, je reçois plus de plantages des applications Python sur mon bureau Fedora que des applications C / C ++ (en fait, aucune des applications C / C ++ sur mon bureau ne plante, maintenant que j'y pense). Exceptions des membres manquants == tellement plus faciles à développer et à maintenir des applications, non?
h) Vitesse. Oui, un grand nombre de développeurs super méchants ont déployé énormément d'efforts dans les exécutions de langage pour rendre JS presque la moitié plus rapide qu'un compilateur C de bas niveau qu'un seul collège junior pourrait écrire en quelques uns. mois. Et LuaJIT est dans le même bateau que JS en termes de limitations de langage fondamentales, mais parvient malgré tout à faire mieux que chaque implémentation JavaScript. Les gens qui ne comprennent pas ce que font réellement toutes les optimisations JS dans V8 ou autresaime prétendre que le JS peut faire des choses incroyables en termes de vitesse, mais la réalité est que toutes ces optimisations sont fondamentalement juste "essayer très dur d'analyser le code pour trouver des types de variables et ensuite le compiler comme un type retardé statiquement typé le compilateur du langage le ferait. " Oh, et il y a le traçage, mais le traçage fonctionne également sur les langages typés statiquement (et fonctionne mieux en raison du manque de garde de type dans le code machine généré). Pas une seule de ces optimisations de whizbang n'a été inventée par ou pour JS, en fait; la plupart proviennent de JVM de recherche (Java is evil!) ou de langages OOP classiques (les prototypes sont géniaux!).
i) Aucun IntelliSense n'est même possible. Vous voulez voir quelles méthodes existent sur cette variable que vous avez là à la ligne 187 de foo.js dans votre éditeur de texte? Dommage. Parcourez le code jusqu'à ce que vous compreniez où il a été initialisé, puis parcourez le code pour découvrir ce que contient son prototype. Et puis j'espère qu'il n'y a pas de code qui change dynamiquement le prototype derrière votre dos. En fait, il suffit de l'exécuter dans un navigateur et de définir des points d'arrêt, car trouver quoi que ce soit d'utile sur la valeur d'une autre manière est fondamentalement impossible pour une base de code plus grande que les sites toy_web_app.html que les apologistes JavaScript utilisent pour glorifier la facilité et la simplicité de JavaScript. Certains éditeurs de code s'efforcent vraiment de faire mieux, et réussissent presque un peu pour les cas très simples, parfois, une fois.
j) Aucun avantage. JavaScript n'est même pas spécial par rapport à d'autres langages typés dynamiquement. Il n'est pas capable de faire quoi que ce soit d'intéressant du tout qui ne peut pas être fait par Lua, Python, Ruby, etc. Aucune des implémentations JS n'est plus rapide que LuaJIT ou PyPy ou diverses autres implémentations JIT avancées d'autres dynamiques les langues. JS n'a pas de côté positif par rapport à d'autres langues couramment disponibles. Oh, sauf qu'il s'exécute nativement dans un navigateur Web sans plugin. C'est la seule raison au monde pour laquelle il est si populaire. En fait, c'est la seule raison pour laquelle cet événement existe. Si quelqu'un il y a 10 ans venait de penser, "diable, laissons tomber une langue existante bien conçue et bien établie dans notre navigateur et demandons aux autres gars de faire de même au lieu de faire en sorte que tout le monde utilise ce petit hackjob loufoque que NetScape a proposé ", le Web serait bien différent (meilleur) aujourd'hui. Imaginez simplement l'avenir si Chrome déposait Python dans Chrome comme langue prise en charge. Ou imaginez ceci: Google dépose C / C ++ dans Chrome en tant que langue prise en charge (http://code.google.com/p/nativeclient/).