Here’s a quick line-up of some smelly jQuery code! “Code smells” are pieces of code that do for your eyes what bad smells do for your nostrils, and usually result in erroneous or harder-to-maintain code. I have no doubt that at least half of you will think that I’m wrong about at least half of these.
Before you stop paying attention, I’d like to wish everyone a Happy New Year! I hope you find the new design more consistent and cleaner.
May the flaming commence…
Prefixxing all jQuery objects with “$”
It’s ugly, and my text editor doesn’t like it! But mainly, it’s ugly, and is only useful for beginners. Hungarian notation is a hotly debated technique — like Marmite (and Jade Goody?), you either love it or hate it!
var $body = $('body'); $body.click(function(){ $this = $(this); }); |
I won’t say much more; I appreciate that it’s a sensitive topic for some and is mostly about personal preference.
Concatenating a bunch of things together to make a selector
I see a lot of this! It looks dirty, and just screams, “I’m succumbing to the API because I don’t know what else to do!”
$('.' + className + '[' + attrLookup + '^=' + attrPrefix ']:not(.' + notClass + ')'); |
This is why I think jQuery needs some other way of filtering DOM elements (possibly something like my filter
hack). For now, seperating out our selectors will have to suffice:
$('.' + blah.className) .filter('[' + attrLookup + '^=' + attrPrefix ']') .not('.' + notClassName); |
To be truthful, I’m on the fence with this… Maybe I’m just against string concatenation!
Going over the top with chaining
Some developers have obviously been dared to never exit a chain, ever!
$('a').addClass('reg-link') .find('span') .addClass('inner') .end().end() .find('div') .mouseenter(mouseEnterHandler) .mouseleave(mouseLeaveHandler) .end() .explode(); |
Long chains are okay, as long as you’re not doing a massive amount of DOM traversing in them… they can become unwieldy beasts!
Not caching collections
$('a').click(function(){ $('a').not(this).addClass('wow'); }); |
Cache please!
var anchors = $('a'); anchors.click(function(){ anchors.not(this).addClass('wow'); }); |
That is, unless you have a good reason not to, e.g. new anchors are constantly being added to the document.
HTML
Long strings of HTML scarring your otherwise beautiful code. Keep the HTML… in the HTML, no in the JavaScript!
$('#something') .append('<div class="gall"><a href="javascript:void(0)">Linky</a></div>') .append('<div class="gall"><a href="javascript:void(0)">Linky</a></div>') .append('<button onclick="app.doStuff()">Button</button>'); |
I added a couple of other code smells (really bad ones!) in there. Please, oh please, learn how to use jQuery for your event handling!
Here’s a nicer smelling (and more readable) alternative:
var div = $('<div/>').addClass('gall').append( $('<a/>').click(function(){ return false; }) ); $('#something') .append(div) .append(div.clone(true)) .append( $('<button>Button</button>').click(function(){ app.doStuff(); }) ); |
Leave a comment: Submit your own code smell! Or… tell me why I’m wrong!
Thanks for reading! Please share your thoughts with me on Twitter. Have a great day!
Great article. I’m on the fence about using the $ prefix with jQuery objects. I read that Ben Nadel article too. Yes, it succumbs to Hungarian notation technically, but I still wouldn’t call it a bad practice.
Hi James. Code smells eh? That’s a polite way of putting it.
2 points: prefixing is spelled incorrectly in your first heading. Also, I wouldn’t go as far to say that the dollar prefix is ‘Hungarian notation’, since Hungarian notation uses letters to indicate the type of variable to which it refers.
But, I take your point. I quite like the dollar prefix. 😉
@Shane – The main idea is that the prefix refers to what type of variable/object it is. I’d imagine that whether you use letters or a symbol is moot.
But, I’m the same as you. It’s comfortable to use the $ symbol – good practice or not. 🙂
For #2 (query concatenation) check out my sprintf snippet:
Sprintf in Javascript on Snipplr
Your example would then become:
I prefer the filter technique you mentioned, but the string formatting is very useful in general.
Nice post, and the last one about the html…. I get really angry when I see that!!! 🙂
James, these are all great tips! I agree with almost all of your points of view, with a few exceptions:
* Prefixing your jQuery objects is not always a bad thing, especially when you work in a production team, and you are most likely sharing your code with others. That way, they have more chance of understanding what type of object they are dealing with. This could be taken overboard, but in small doses, it really cuts down on production time.
* I am a firm believer in clean HTML. Therefore, if you’re needing buttons and sections simply for behavioral reasons (e.g. handles for moving/sorting, etc), you should keep them in the javascript, and only add when available (via progressive enhancement) instead of keeping it “in the HTML.”
Other than that, fantastic article. I always enjoy your posts!
Jason Featheringham
Hi,
what I hate particulary is when people haven’t understood how jQuery works and do stuff like this:
instead of doing this:
Just a silly example to point out what I mean.
@Jason, sweet idea, although it’s still a shame that jQuery doesn’t provide an alternative API for complex selections.
@David, totally agree! That annoys me too!
@All, The “$” is a tricky topic and it is all down to taste. I can see uses for it when working in a team (as Jason F. mentioned) or perhaps when writing code/tutorials geared towards beginners.
@Jason F, yes, definitely, you shouldn’t need to create too many DOM structures in your JavaScript… either progressively enhance what’s already there or use templates. I wasn’t saying to just stick it all in the document, but perhaps, with large chunks of behavioural HTML, you could store it in its own file and asynchronously request it when needed.
When I’ve written plugins that require a bunch of dynamically made elements to be injected into the page, I always keep the template code for that HTML in the javascript. It’s cleaner and it keeps the plugins simple to use.
That said, I think that there is a limit to what should be kept in the javascript. If you’re getting highly nested HTML, perhaps there is a better solution.
@Shane and others re: Hungarian Notation questions…
Go check out the previously mentioned Ben Nadel article that discusses this in depth, here: http://www.bennadel.com/index.cfm?dax=blog:1778.view.
Personally, I am in agreement that it could be construed as Hungarian, but I have yet to decide whether I care if that’s good or bad practice in the jQuery world (I am, however, leaning towards an anti-Hungarian position toward coding styles in the rest of my universe).
Either way, just thought I’d pass along the reference, for those who are interested.
Cheers,
Lelando
Great post and some good points mentioned! You talked about over-chaining, but I find there are some people that don’t chain when it’s acceptable to… or they just don’t know that you can chain in jQuery. For example I’ve seen this way too often:
Not only are is this code not making use of a little chaining, but it’s scanning the dom each time instead of caching the element 🙁
I might even dare to say that sometimes jQuery itself is a code-smell!
Sometimes people just like jQuery too much and try to use it where some other alternatives may be more suitable – think heavier “full stack Web 2.0” apps, where something like ExtJS, Dojo, etc. might be better.
I would have to disagree with you on the HTML. How is spreading your elements all over your javascript easier to read than having it all in one append? How is having it spread over 14 lines easier to read than having it spread over only four lines? Why go through all the trouble of telling jQuery to build this element, append it to this element, clone it and append it again, then build another element and append that, when you can just give it the description and have it build the element for you? In fact, it would probably be a huge performance boost to just have all those appends in one string and append that one string, shortening it down to two lines in your line spacing. Unless you take off your HTML glasses when you put on your Javascript glasses, or you’re trying to use jQuery with minimal knowledge of HTML (heaven forbid), your argument for readability is moot. I also have to agree with Jason Featheringham on progressive enhancement. Why have elements in your HTML that will be revealed through Javascript and will do nothing if Javascript is not enabled? Just append them using Javascript when they are needed, and don’t put more junk through your user’s connection than they need.
Jade Goody is an ‘it’ now? That’s a bit harsh 🙂
@Ryan, hmm, I probably should have expanded a bit on that point. I think it’s fine to keep a big chunk of HTML at the top of all your logic, out of its way, but when your JS is littered with HTML strings, then it becomes a problem.
@Lelando, thanks for the link. I tend to see hungarian notation as anything that indicates the type of variable… So,
$var
is really the same asjQvar
.@Jordan, totally agree. That really is pitiful code… but an all too often occurrence with beginners. I think the main thing to get across to new jQuery users is that everything returns a jQuery object, apart from the getters (
text()
,html()
etc.). Hopefully knowing this will make them less scared of chaining.@Jani, Yep, I think I agree. You have to choose the right tool for the job… and sometimes that’s not jQuery. 🙁
@Arnold, first, the code in the post was just a tiny example.. I’ve seen much worse, and I’m sure you have too. I never mentioned progressive enhancement in the post; perhaps I should have. Obviously, it’s best to progressively enhance already-existing elements, and I feel that when you want new ones, either create them via the DOM (as it was intended, not JUST with
innerHTML
) or use a simple JS template engine. Plus, the solution I offered really was better than the HTML string solution — first, I was able to add events using jQuery’s event mechanism (always a better choice) and, if needed, I can easily reference those inner elements (like the anchor) without having to subsequently traverse the DOM looking for it… E.g.@Pete, that was not entirely intentional… 😉 I only added the Jade bit after writing the post. I don’t like speaking ill of the deceased, but during her life, she wasn’t much more than an “it” to me…
You’re doing it wrong. You wouldn’t store the object as a variable, you’d just do this
And with the $ it shows you the difference between jQuery objects and normal Javascript ones. But it’s down to preference.
And the messy selector thing. What I’d do is this…
It’s not the same however your example wasn’t exactly practical :p
Chaining is very useful, what’s the cleaner alternative?
I aggree with you on the HTML bit, I’ve made a few Greasemonkey scripts where that becomes a huge problem. But when properly formatted it’s ok. I find storing bigger chunks of HTML at the start of a JS file keeps them out of the way.
Nice article though, it’s refreshing to see an interesting jQuery post.
@Ben, obviously the
$body
thing was an example… In real life, you’d just call the method straight off it.And I don’t see how
$('.myClass').attr('foo');
would solve the selector problem. Could you expand on this?Well that was just a quick example, it wont solve your exact problem.
But I think the bunched up selector thing is the case for any programming language. I was just showing you a method which would break it up slightly.
“It’s ugly, and my text editor doesn’t like it!”
What a non-reason. Get a decent editor, NetBeans is highly recommended!
Cache selectors! Everybody should but most don’t!!
if inside an enclosure or function i like to preserve the parent element or ‘this’ by doing:
_this = $(this);
or _el = $(‘#id’)
Some good stuff on here. I’m pretty bad at adding HTML strings instead of defining new jQuery objects. Its always important to train good coding habits! Cheers
From Standard ECMA-262, 3rd Edition: Section 7.6: Identifiers:
I think the usage in jQuery, Prototype, and MooTools is appropriate. I don’t use it in my own code because I *do* so often use a library that uses the dollar sign, and I also use PHP often, so there’s a bit of delay looking at code as I think … “what am I looking at” … dollar sign prefixes in JS code are not a help to me.
If anchors are continually being added to the page after “ready”, and you need to handle events on them… you can use:
so, you still have no excuse for not caching DOM selections in the case of event handling.
alternatively, if there are going to be a ton of anchors, then registering click handlers on all them can become an inconsiderate resource hawg — so you might instead choose to register just a single click handler on a wrapper element, and then only perform some logic if the event target is an anchor you are interested in adding behavior to.
When it’s necessary to store html in your jQuery, I’ve been ‘prettifying’ it via back slashes:
That allows me to keep it formatted in a relatively sane format.
Chaining can get pretty sick if you break the chain, then return to the parent and so on. If you the only developer of this code, no problem. But if you share you masterpiece you should probably separate it.
Using some Markers like $ or j or whatever is a good idea, like using datatypes in php (s,i,a or o before the variable name).
Interestingly enough, thank you:)
@David Müller’s comment made me go back and look at my $().each() statements. I uncovered another code smell: if you’re using only jQuery statements in your function passed to the $().each() function, then you probably don’t need the $().each().
For example, this…
should be…
As I have tweeted before using the $-sign for jQuery variables seems so ugly and Hungarian but after reading Joe Crawford’s comment that the dollar sign is intended for use only in mechanically generated code makes me wonder, what if…
Anyway I have never needed to use the $-sign for cached jQuery vars nor do I need to use markers like s, i, a or o for datatypes in any language including PHP. It would even create messier code.
It annoys the hell out of me when I see this:
closest() please, or at least parents().
Hey James,
You can just as “easily reference those inner elements without having to subsequently traverse the DOM looking for it” if you use an HTML string. For example:
First of all, great article. If anything articles like this make us step back and consider what we are doing on a day-to-day basis. And then realize it doesn’t always stroke with our ideals..
Then, to avoid further confusedness on the subject, the dollar sign ($) has nothing at all to do with Hungarian notation. Really. And though I understand why people would make the mistake thinking it does, saying it does is an error in the same league as how some people insist on talking about Ajax when they just mean plain old DOM-scripting (ie, working with the DOM without server communication).
In Hungarian notation one would use alphabetic characters to flag a variable as a certain type. Most, if not all, types are clearly defined (check wikipage for infos) so as not to create the confusion which you are trying to solve. No sense everyone keeping his own preferred list of notations right?
What you are talking about is what they call a ‘Sigil‘. Which is using symbols to show a datatype or scope. Problem with this is that, again, you should be consequent and thorough with this. Which you can’t in JavaScript since certain characters just aren’t permitted.
This, for me, is reason enough to stay clear of overusing the $ symbol for purposes other then a framework-interface element. Besides agreeing with what’s said before about how this overuse doesn’t really mix well with (for instance) PHP code.
Because, like you, I have a distaste for mixing of code. So yay and full agreement on the bit about long strings of HTML. So much so that I’ve written a tiny jQuery extension for this, like most of us I guess. Nevertheless I thought I’d include this here. Either for those who haven’t thought about it or for those who have a far better solution (these people will probably tell me off for doing it wrong ;))..
*note, in my code I got that IF statement on one line, thought I’d break it up so it was a little more readable.
Maybe someone can use this.
Thanks again for the article 🙂
In fairness, most of these are nitpicks about how people write jQuery, not jQuery itself.
> it’s still a shame that jQuery doesn’t provide an alternative API for complex selections.
It does, and a very efficient one. Javascript! Just use .filter() and write your filter code in a function. Complex selections are, well, complex and also relatively rare, so it would be a shame to add a lot of code size to jQuery to handle an infrequent need.
I agree about big chunks of HTML in the source; it’s often better to put a template into the file with display:none then use jQuery to clone/fill it.
@beeman, that was my attempt at adding a bit of wit to a post. I wasn’t serious.
@Joe, surely, then, its usage as I’ve described should not be advised, since its only in the language to accommodate machine generated code?
@matt, yes, event delegation is a viable solution in that situation.
@Darrel, But is that really any better? Large amounts of HTML should be stored elsewhere, not in the JS source.
@Adam, yep, good point!
@Eric, yep, I agree, although
parent().parent()
is always going to be faster thanparents()
orclosest()
.@Karl, yeh, I guess, but there’s still an overhead caused by having to do the search.
@Patrick, thank you for the clarification on the “Hungarian notation” term. I like your
createEl
function, although, jQuery (without any mods) can be used to similar effect:@Dave,
I never stated otherwise. jQuery’s fantastic!
filter()
certainly is very useful but there are still situations that would be better accommodated by a cleaner and more terse API (and it wouldn’t take that much code to implement).A Nice article, a couple of things though:
That code is much slower then
Looping it 200 times, I get 441ms with the “not smelly” method and 180ms with the smelly method.
.append is a very expensive method in jquery 1.3.2. Try and only append once instead of multiple times. it is much slower then traversing a small jQuery snippet like Karl suggests.
@Josh, good point. I did consider performance, but, with the ever-increasing speed of browsers, readability is becoming more of an issue and we’re not having to make so many compromises because of performance.
When performance is a prime concern, then frankly, I wouldn’t necessarily recommend using jQuery in the first place.
In fact, if you were using jQuery, then I might recommend that you use templates instead of creating DOM structures inline with other program logic. The code I posted was targeted at the average jQuery user — someone who’s not concerned about performance and typically doesn’t pay much attention to best practices. An increase in readability can’t harm such individuals, or their code.
I’m all for caching selectors appropriately, but doing so before a click event, in the global scope? Unless you’ve got a very basic app, that’s kind of dangerous.
The $ operator is just a namespace hack, I fail to see why it’s a problem. Would you rather preface all your jQuery calls with jQuery.Something? Doesn’t seem much better. But, yeah, opinion.
in reference to your last point (“Long strings of HTML scarring your otherwise beautiful code”), you may find this useful: http://saroskar.github.com/PaJes/
It’s a small JS library that allows you generate innerHTML segments using clean, functional JavaScript code. (Sorry for the shameless plug). For example,
@James it’s only better in that it’s more readable. If you have to put the HTML inline with your jquery, it might as well be readable.
Obviously, one should avoid doing that, but as stated, when trying to componentize one’s code, the more self contained it can be, the easier to maintain/reuse it down the road.
I usually inline markup that is strictly being added for purely visual reasons (hacks to deal with corner rounding, or divs holding purely decorative background images, etc.). You hate storing that stuff in the markup itself, as it’s more style related than content related.
This article smells 😉
I am sure your intentions are good – prompting people to have another look at their code. But your list only shows blunt statements that don’t make a case.
Give me some good reasons why “it’s best to progressively enhance already-existing elements”, and I am ready to follow you. Otherwise I just consider this a matter of personal taste. Same for $, concatenating or chaining.
I’m very much in the pro-camp on prefixing jQuery objects with
$
. It makes your intentions so much more obvious. Consider this:You know immediately just by looking at the method signature what type of object is expected. You never have to search back through your code to see if
$div
is a jQuery object or just a plain DOM Element.Regarding
.append()
being very slow: You’ll get differing results depending on what you’re appending to. If you’re appending to an element which is in the document, then the browser has to recalculate styles which is a relatively expensive operation. If you’re adding to something which isn’t in the DOM yet, then it only needs to do this once at the end and it’s much faster.In your HTML example, your “non-smelly” code leaves out the link text “Linky”. Adding this is no problem (
$('<a/>').text("Linky").click(function(){ ...
)but it adds another function call, and makes your “more readable” code a bit more removed from the actual HTML.
On the whole, I think, I’d probably go for something like this:
I agree with most of the responses concerning the appending html section. I just think trying to abstract things, trying to make them look more ‘readable,’ or attempting to use better programming practice is simply the wrong philosophy here.
As Josh Powell said, performance is clearly an issue.
To build off of that, maintainability is much simpler with one append than it is with your solution, The only reason anything should ever become more ‘complex’ (from the readability standpoint) is to improve efficiency or performance. In this case, this simply doesn’t cut it.
Alternatively, if you’re already using jQuery for other reasons then you should be concerned with gaining the best performance.
It’s not necessarily true that new browsers are universally faster and in any case someone has to pay the price for inefficient code whether it’s time, disk wear or electricity bills.
Great read
is this too much chaining?
I wondered what I could smell Eliazer. Surely there was another method you could use?
Inspired by this article, I’ve been on an .each() hunt of my own code and eliminated almost all of them.
Of course 1.4’s ability to do things like
may be an .each() in disguise but the performance improvements mean I no longer care (despite what I said in the bad old days of 1.3)
My pet-hate at the moment is so-called “prettified” code. Please God, it ain’t f***-in legible!!!
“When performance is a prime concern, then frankly, I wouldn’t necessarily recommend using jQuery in the first place.”
Agreed. Personally, I like MooTools better.
The jQuery developers themselves use $var in the jQuery code. It’s an extremely useful way of differentiating a jQuery results object from the (very similar) raw HTML element object (or any other type of var for that matter, but that’s the specific case I believe it’s designed for).
var div;
Is that an HTML div, or a $(“div”)? I have no idea. Unless I use:
var $div;
regularly, in which case I know with certainty without having to scroll back up through my code to find out.
So yeah: this article smells 🙁