API Design and jQuery

I often heard that jQuery made some bad API decisions. Although jQuery is not my favorite library, it is the library that I used most often, and it is difficult for me to point out specific errors in the design of the API or how it could be improved.

What parts of the jQuery API could be better implemented , how could different ones be implemented, and why could another implementation be better implemented?

The question applies to both individual low-level API details and high-level API data . We are talking only about errors in the API, and not about the flaws in the design / purpose of a high-level library; jQuery is still a DOM manipulation library oriented around the selector mechanism.

Due to the need to freeze the API in popular jQuery libraries, it is stuck in its current state, and developers are doing fine. As you can see from the recent .attr vs .prop change, developers do not have the flexibility to change any of their design decisions (which is a shame!).

One concrete example that I can think of will be

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

vs

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

which is quite confusing that I have to double check the frequency of the parameters.

Please do not compare the jQuery library with full-fledged frameworks such as dojo and YUI, and complain about the lack of functions.

+43
javascript jquery design api api-design
May 19 '11 at 19:28
source share
4 answers
  • .load() overloaded with completely different behavior depending on the arguments passed

  • .toggle() overloaded with completely different behavior depending on the arguments passed

  • jQuery() function overload is probably too big.

  • the .attr() you mentioned. The difference from the properties was to be an immediate IMO.

  • .map( key,val ) , but $.map( val,key ) , and this values ​​are different.

  • non-standard selectors should be excluded from Sizzle IMO. Javascript-based selector mechanisms should be obsolete for several years, and people connected to proprietary selectors will have a more complex transition

  • bad name method of methods like .closest() or .live() . What exactly are they doing?

  • I recently discovered that you cannot set the standard width and height attributes through the props argument when creating a new element. Instead, jQuery runs its own width and height methods. IMO, spec attributes should be given priority value, especially since width and height can be set via css .

 $('<img/>', { css:{width:100, height:100}, width:100, // <-- calls method, why? height:100, // <-- calls method, why? }); 
  • $.get() and .get() completely different.

  • .get() and .toArray() identical when passing arguments

  • toArray() and $.makeArray() do the same. Why didn't they give them the same name as .each() and $.each() ?

  • two different methods of delegating events. .delegate() reasonable, and .live() magic "wow, it just works!" one.

  • .index() overloaded with three behaviors, but their differences can be confusing

  // 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'); 

The first is understandable if you remember that it only works with the first element

The second method makes the most sense, since jQuery methods usually work with the entire collection.

The third is completely confused. This method does not indicate which selector is the collection and which selector represents the element whose index you want to get from the collection.

Why not just eliminate the third one and ask people to use the second one like this:

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

Thus, it is more closely related to the rest of jQuery, where .index() works with the entire collection.

Or at least change the meaning of the selectors so that they fit better:

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



There is still something to think about.

I have some problems with jQuery event handling / storage. It is praised because it does not add functions to the on[event] properties, which can close around other elements, creating memory leaks in IE. Instead, it places the easy expando property, which maps to a jQuery.cache that contains handlers and other data.

I believe that it then attaches the handler, which in turn calls the handler that you assigned. Or something like that.

No matter which system does not matter. The thing is, the connection between the element (s) and jQuery.cache is that expando.

Why is this so important? Well philosophically jQuery is not the foundation; this is a library. It looks like you can use or not use jQuery functions as a library without worrying about negative effects. However, if you go beyond jQuery when deleting elements from the DOM, you dispute any handlers and other data associated with these elements through the extension, creating a pleasant and completely cross-browser memory leak.

So, for example, something as simple as el.innerHTML = '' can be very dangerous.

Mix this with the jQuery.noConflict() function. This allows developers to use jQuery with other libraries using the global $ namespace. Well, if one of these libraries removes some items? Same problem. I get the feeling that a developer who needs to use a library like Prototypejs along side jQuery probably doesn’t know enough JavaScript to make the right design decisions and will be prone to such a problem as I described.




As for the improvements in the framework of the supposed library philosophy, as far as I know, their philosophy is “Do more, write less” or something like that. I think they do it very well. You can write very concise but expressive code that will do a great job.

While this is very good, I think of it as something negative. You can do so much, so easily, it’s very easy for beginners to write very bad code. It would be nice if there was a “developer build” that logged warnings about misuse of the library.

A common example is running a selector in a loop. Choosing a DOM is very easy to use, it seems that you can just run the selector every time you need an element, even if you just ran this selector. An improvement, I think, would be for the jQuery() function to register reuse of the selector and give a console note that the selector can be cached.

Since jQuery is so dominant, I think it would be nice if they not only simplified the work with JavaScript / DOM, but also helped you become the best.

+40
May 19 '11 at 19:42
source share
— -

The way jQuery handles collections compared to individual elements can be confusing.

Say, if we updated some css property in a set of elements, we could write

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

The installer will update the background color of all relevant elements. The getter, however, assumes that you are only interested in getting the value of the first element.

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

MooTools will return an array containing the background colors of each corresponding element, which seems more intuitive.

JQuery naming conventions simplify conciseness rather than clarity. I like Apple's strategy when naming things:

Better to be clear than concise.

And here is an example of a method name from a mutable array class ( NSMutableArray ) in Objective-C.

 removeObjectAtIndex:(..) 

He does not try to be smart about what needs to be removed or where he is being removed. All the information you need to know is contained in the name of the method. Compare this to most jQuery methods like after and insertAfter .

If someone can intuitively find out what after or insertAfter does without reading documents or source code, then this person is a genius. Unfortunately, I'm not alone - and for now, I still have to go to the documentation to find out what the hell fits where using these two methods.

+8
May 19 '11 at 20:10
source share

Included in jquery:

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

Not in 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(); 

Why does this bother me? Not because we don’t have the above methods in the library, it’s just silly, and I hate it if we ever (plus, most will not work with browsers), but I hate these short methods place: $.post(); Sends an ajax request through a message.

Know what covers everything on this list? The only function that is not short is $.ajax , it is fully functional and covers everything, you can even configure it to store default values ​​and, in fact, create all these short hands. You can create your own methods if you want to call this ajax call (which they all do).

Here, where it really is REALLY annoying.

Someone writes all their code using an abbreviation:

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

Well, oh wait, we want to change this to the XML feed that we get from the message, we also need to do something before and after publishing. Oh, let's just switch to the short-handed method.

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

Oh wait, I can't just replace the word, the whole structure is everywhere.

This and especially for things like $ .load (), the cross-lines in which PHP has such a hateful API, they try to do what they should not do.

To extend this beyond AJAX calls, see the animation snippet. We have calls slideUp, slideDown, fadeIn, fadeOut, fadeToggle, show and hide. What for? Where is my slide on the left, slide to the right, slide, advance, teleport and all that we can think of? Why not just stick with $ .animate () and let someone write a plugin if we want to get these effects. Infact, someone wrote a plugin, jQueryUI extends the animation. This is just crazy and leads people to not know that some effects create CSS rules in their divs that ultimately collapse what they want to do later.

Keep it clean, keep it simple.

+5
May 19 '11 at 20:17
source share

patrick dw hit most of the points in his (fantastic) answer. Just add a few more examples to your collection.

The API is supposed to be consistent; and jQuery succeeds in many areas (being very consistent for returning a jQuery object / getting value, as expected in many cases). However, in other situations this is not so good.

Method Names As Patrick already pointed out; nearest () is the name of the crap method. prev () and next () appear as if they were doing the work prevAll () and nextAll () .

delay() confuses a lot of people: In the following example, what do you expect? ( what is really going on? )

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

Method Arguments Many tree traversal functions are inconsistent with what they take; they all accept a mixture of selectors, objects, and jQuery elements, but none of them are consistent; which is bad, considering that they all perform similar tasks. Check the closest () , find () , siblings () , parents () , parent () and compare the differences!

Internally, the “core” jQuery originally contained a lot of interwoven methods that the development team struggled to share (and do it very well) with previous releases. Internal modules such as css, attributes, manipulations, and moving all that were all included in the same large package.

+5
May 19 '11 at 20:38
source share



All Articles