43 votes

Conception d'API et jQuery

J'ai souvent entendu dire que jQuery avait pris de mauvaises décisions en matière d'API. Bien que jQuery ne soit pas ma bibliothèque préférée, c'est celle que j'ai utilisée le plus souvent et je trouve difficile de pointer du doigt des erreurs spécifiques dans la conception de l'API ou la manière dont elle aurait pu être améliorée.

Quelles parties de l'API de jQuery auraient pu être mieux faites, comment aurait-il pu être mis en œuvre différemment et pourquoi Cette mise en œuvre différente serait-elle meilleure ?

La question s'étend à la fois détails individuels de bas niveau de l'API et détails de haut niveau de l'API. Nous ne parlons que des défauts de l'API plutôt que des défauts de la conception de haut niveau et de l'objectif de la bibliothèque. jQuery est toujours une bibliothèque de manipulation du DOM centrée sur un moteur de sélection.

En raison de la nécessité de geler les API dans les bibliothèques populaires, jQuery est bloqué dans son état actuel et les développeurs font un excellent travail. Comme on peut le voir par la récente .attr vs .prop changer les développeurs n'ont pas la possibilité de modifier leurs décisions de conception (ce qui est dommage !).

Un exemple spécifique auquel je peux penser serait

$.each(function(key, val) { })

vs

$.grep(function(val, key) { })

ce qui est suffisamment confus pour que je doive fréquemment revérifier les paramètres.

Veuillez ne pas comparer le système jQuery bibliothèque à part entière cadres comme dojo et YUI et se plaignent du manque de fonctionnalités.

40voto

user113716 Points 143363
  • .load() est surchargé avec un comportement entièrement différent selon les arguments passés

  • .toggle() est surchargé avec un comportement entièrement différent selon les arguments passés

  • une surcharge trop importante de la jQuery() fonction peut-être.

  • le site .attr() que vous avez mentionné. La distinction avec les propriétés aurait dû être immédiate, selon l'OMI.

  • .map( key,val ) mais $.map( val,key ) et le this sont différentes.

  • Les sélecteurs non standard auraient dû être tenus à l'écart de Sizzle IMO. Les moteurs de sélection basés sur Javascript devraient devenir obsolètes dans quelques années, et les personnes accrochées aux sélecteurs propriétaires auront une transition plus difficile.

  • mauvaise dénomination des méthodes comme .closest() ou .live() . Que font-ils exactement ?

  • J'ai récemment découvert que vous ne pouvez pas fixer la norme width et height par l'intermédiaire du props lors de la création d'un nouvel élément. jQuery exécute son propre argument de type width et height à la place. OMI, les attributs de la spécification auraient dû être prioritaires, d'autant plus que width et height peut être réglé via css .

    $('<img/>', { css:{width:100, height:100}, width:100, // <-- calls method, why? height:100, // <-- calls method, why? });

  • $.get() et .get() sont totalement différentes.

  • .get() et .toArray() sont identiques lorsqu'ils ne passent aucun argument

  • toArray() et $.makeArray() font effectivement la même chose. Pourquoi ne leur ont-ils pas donné le même nom comme .each() et $.each() ?

  • deux différents délégation d'événements méthodes. .delegate() la personne sensible, et .live() la magie "wow, ça marche !" un.

  • .index() est surchargé de 3 comportements, mais leurs différences peuvent être déroutantes

    // v---get index v---from collection (siblings is implied) $('selector').index(); // v---from collection v---get index $('selector').index(element); // v---get index v---from collection $('selector').index('selector');

La première est compréhensible si l'on se rappelle qu'elle n'opère que sur le premier élément

La seconde est la plus logique puisque les méthodes jQuery généralement opérer sur une collection entière.

La troisième est totalement confuse. La méthode ne donne aucune indication sur le sélecteur qui représente la collection et sur le sélecteur qui représente l'élément dont vous voulez l'index dans la collection.

Pourquoi ne pas simplement éliminer le troisième, et faire en sorte que les gens utilisent le deuxième comme ceci :

 // v---from collection      v---get index
$('selector').index( $('selector') );

De cette façon, il s'intègre mieux au reste de jQuery où .index() opère sur l'ensemble de la collection.

Ou au moins inverser le sens des sélecteurs pour mieux s'intégrer :

 // v---from collection   v---get index
$('selector').index('selector');

En voici une autre à laquelle vous pouvez réfléchir.

J'ai quelques inquiétudes concernant le système de gestion des événements et de stockage des données de JQuery. Il est loué parce qu'il n'ajoute pas de fonctions à on[event] qui peuvent se refermer autour d'autres éléments, créant ainsi des fuites de mémoire dans IE. Au lieu de cela, il place une propriété expando légère, qui correspond à une entrée dans le fichier jQuery.cache qui contient les gestionnaires et d'autres données.

Je crois qu'il attache ensuite un gestionnaire qui invoque à son tour le gestionnaire que vous avez assigné. Ou quelque chose comme ça.

Quel que soit le système, cela n'a pas vraiment d'importance. L'essentiel est que le lien entre l'élément ou les éléments et le(s) jQuery.cache c'est cet expansif.

Pourquoi est-ce un problème ? D'un point de vue philosophique, jQuery n'est pas un framework, mais une bibliothèque. Il semblerait qu'en tant que bibliothèque, vous devriez pouvoir utiliser ou ne pas utiliser les fonctions jQuery sans vous soucier des effets négatifs. Pourtant, si vous sortez de jQuery lorsque vous supprimez des éléments du DOM, vous avez rendu orphelins tous les gestionnaires et autres données associés à ces éléments via l'expando, créant ainsi une fuite de mémoire agréable et entièrement inter-navigateurs.

Ainsi, par exemple, quelque chose d'aussi simple que el.innerHTML = '' pourrait être très dangereux.

Ajoutez à cela le jQuery.noConflict() caractéristique. Cela permet aux développeurs d'utiliser jQuery avec d'autres bibliothèques qui utilisent l'option $ espace de noms global. Et si l'une de ces bibliothèques supprime certains éléments ? Même problème. J'ai l'impression que le développeur qui a besoin d'utiliser une bibliothèque comme Prototypejs à côté de jQuery ne connaît probablement pas assez JavaScript pour prendre de bonnes décisions de conception, et sera sujet à un problème tel que je l'ai décrit.


En ce qui concerne les améliorations dans le cadre de la philosophie de la bibliothèque, pour autant que je sache, leur philosophie est "Faire plus, écrire moins" ou quelque chose comme ça. Je pense qu'ils y parviennent très bien. Vous pouvez écrire un code très concis mais expressif qui fera une énorme quantité de travail.

Bien que ce soit une très bonne chose, d'une certaine manière, je le considère comme un point négatif. Vous pouvez faire tellement de choses, si facilement, qu'il est très facile pour les débutants d'écrire du très mauvais code. Il serait bon, je pense, qu'il y ait un "developer build" qui enregistre les avertissements de mauvaise utilisation de la bibliothèque.

Un exemple courant est l'exécution d'un sélecteur dans une boucle. La sélection DOM est très facile à faire, qu'il semble que vous pouvez simplement exécuter un sélecteur chaque fois que vous avez besoin d'un élément, même si vous avez juste exécuté ce sélecteur. Une amélioration serait, à mon avis, que le jQuery() pour consigner les utilisations répétées d'un sélecteur et indiquer dans la console qu'un sélecteur peut être mis en cache.

Parce que jQuery est si dominant, je pense qu'il serait bon qu'ils ne se contentent pas de faciliter la tâche des programmeurs JavaScript/DOM, mais qu'ils les aident aussi à devenir meilleurs.

8voto

Anurag Points 66470

La façon dont jQuery gère les collections par rapport aux éléments individuels peut être source de confusion.

Disons que si nous devions mettre à jour une propriété css sur une collection d'éléments, nous pourrions écrire,

$('p').css('background-color', 'blue');

Le paramètre met à jour la couleur d'arrière-plan de tous les éléments correspondants. Le getter, quant à lui, suppose que vous êtes uniquement intéressé par la récupération de la valeur du premier élément.

$('p').css('background-color')

MooTools renverrait un tableau contenant les couleurs d'arrière-plan de chaque élément correspondant, ce qui semble plus intuitif.

Le site conventions de dénomination pour jQuery favorisent la concision au lieu de la clarté. J'aime la stratégie d'Apple pour nommer les choses :

Il vaut mieux être clair que bref.

Et voici un exemple de nom de méthode d'une classe de tableau mutable ( NSMutableArray ) en Objective-C.

removeObjectAtIndex:(..)

Il ne s'agit pas de faire preuve d'intelligence quant à ce qui est supprimé ou à l'endroit où il l'est. Toutes les informations dont vous avez besoin sont contenues dans le nom de la méthode. Comparez cela à la plupart des méthodes de jQuery telles que after et insertAfter .

Si quelqu'un peut intuitivement comprendre ce que after ou insertAfter fait sans lire la documentation ou le code source, alors cette personne est un génie. Malheureusement, je n'en suis pas un - et à ce jour, je dois toujours consulter la documentation pour comprendre ce qui est placé où quand on utilise ces deux méthodes.

5voto

Matt Points 38395

patrick dw a touché la plupart des points dans sa réponse (fantastique). Juste pour ajouter à sa collection quelques autres exemples.

Une API est censée être cohérente ; et jQuery y parvient dans de nombreux domaines (en étant très cohérent pour renvoyer un objet jQuery/une valeur get, comme prévu dans de nombreux cas). Cependant, dans d'autres situations, elle ne réussit pas aussi bien.

Noms des méthodes Comme l'a déjà fait remarquer Patrick ; le plus proche() est un nom de méthode de merde. prev() et suivant() semblent faire le travail pour la plupart prevAll() et nextAll() fournissent réellement.

delay() confond beaucoup de gens : Dans l'exemple suivant, que pensez-vous qu'il va se passer ? ( que se passe-t-il réellement ? )

$('#foo').hide().delay(2000).slideDown().text('Hello!').delay(2000).hide();

Arguments de la méthode Beaucoup de fonctions de traversée d'arbre sont incohérentes dans ce qu'elles acceptent ; elles acceptent toutes un mélange de sélecteurs, d'objets jQuery et d'éléments, mais aucune n'est cohérente ; ce qui est mauvais si l'on considère qu'elles font toutes un travail similaire. Consultez le plus proche() , trouver() , frères et sœurs() , parents() , parent() et comparez les différences !

En interne, le "noyau" de jQuery contenait à l'origine de nombreuses méthodes entrelacées, que l'équipe de développement s'est efforcée de séparer (et a très bien réussi), au cours des dernières versions. Les modules internes tels que les css, les attributs, la manipulation et la traversée étaient tous regroupés dans le même gros paquet.

4voto

Incognito Points 10637

Inclus dans jquery :

.post()
.get()
.getScript()
.getJSON()
.load()

Pas dans jQuery :

$.getXML();
$.headXML();
$.postXML();
$.putXML();
$.traceXML();
$.deleteXML();
$.connectXML();
$.getJSON();
$.headJSON();
$.postJSON();
$.putJSON();
$.traceJSON();
$.deleteJSON();
$.connectJSON();
$.headScript();
$.postScript();
$.putScript();
$.traceScript();
$.deleteScript();
$.connectScript();
$.getHTML();
$.headHTML();
$.postHTML();
$.putHTML();
$.traceHTML();
$.deleteHTML();
$.connectHTML();
$.getText();
$.headText();
$.postText();
$.putText();
$.traceText();
$.deleteText();
$.connectText();
$.head();
$.put();
$.trace();
$.delete();
$.connect();

Pourquoi cela me dérange-t-il ? Ce n'est pas parce que nous n'avons pas les méthodes ci-dessus dans la bibliothèque, c'est tout simplement stupide et je détesterais que nous les ayons un jour (de plus, la plupart d'entre elles ne fonctionnent pas avec les navigateurs), mais ce que je déteste, ce sont ces méthodes abrégées partout : $.post(); Envoie une requête ajax par courrier.

Tu sais ce qui couvre tout dans cette liste ? La seule fonction qui n'est pas un raccourci, $.ajax Vous pouvez même le configurer pour qu'il stocke des valeurs par défaut et crée essentiellement tous ces raccourcis. Vous pouvez créer vos propres méthodes si vous souhaitez appeler cet appel à ajax (ce que font toutes ces méthodes).

C'est là que c'est vraiment VRAIMENT ennuyeux.

Quelqu'un écrit tout son code en utilisant la sténographie :

$.getJSON(
  'ajax/test.html', 
   function(data) {
     $('.result').html(data);
   }
);

Ok, oh attendez, nous voulons changer cela en un flux XML que nous obtenons à partir d'un post, nous devons aussi faire en sorte que quelque chose se passe avant et après le post. Oh, passons simplement à la méthode non manuelle.

$.ajax({
  type: 'POST',
  url: url,
  data: data,
  success: success
  dataType: dataType
});

Oh attendez, je ne peux pas juste remplacer le mot, toute la structure est à l'envers.

Ceci, et particulièrement pour des choses comme $.load(), croise les lignes de la raison pour laquelle PHP a une API si détestée, ils essaient de faire des choses qu'ils ne devraient pas faire.

Pour aller au-delà des appels AJAX, regardez la partie animation. Nous avons des appels à slideUp, slideDown, fadeIn, fadeOut, fadeToggle, show, et hide. Pourquoi ? Où sont mes slide left, slide right, slide in, slide out, teleport, et toutes les autres choses que nous pouvons imaginer ? Pourquoi ne pas simplement s'en tenir à $.animate() et laisser quelqu'un écrire un plugin si nous voulons ces effets. En fait, quelqu'un a écrit un plugin, jQueryUI extends animations. C'est tout simplement fou, et cela conduit les gens à ne pas savoir que certains effets créent des règles CSS sur leurs divs qui finissent par gâcher ce qu'ils veulent faire plus tard.

Gardez-le pur, gardez-le simple.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X