Hacker News new | past | comments | ask | show | jobs | submit login
The jQuery Divide:Understand where jQuery ends and JavaScript begins (slideshare.net)
157 points by binarray2000 on Apr 10, 2011 | hide | past | web | favorite | 76 comments

I'm not so sure I buy the premise that jquery is unsuitable for large scale applications. I think it is based on an assumption that jquery should provide a framework for these things, but really - what jquery is, is a framework for the controller layer of an application. If you want to use it, you have to provide the model level framework your self. I don't think this is the fault of jquery anymore than it would be the fault of Sinatra.rb to not provide the functionality of Rails.

jQuery as commonly used leads, in my personal experience, to hard-to-maintain programs. Just like Ruby on Rails, or Perl.

There is also anecdotal evidence that jQuery qua jQuery has some fundamental limits. I worked on a largish jQuery application, written by ninja badasses, and it creaked a lot more than it should have for its size.

Comparable systems built on YUI seemed to have more structure. I actually went through the exercise of converting a prototype from jQuery to YUI3, and spent a lot of time working out their respective "philosophies". (see http://jsrosettastone.com)

There are newer frameworks (eg JavelinJS) that aim to be to jQuery what jQuery was to other frameworks.

    I worked on a largish jQuery application, 
    written by ninja badasses
I don't think those "ninja badasses" were as good as you're describing them.

If they were, they would realize that jQuery is not a framework that structures your application, but just a neat and light library that provides syntactic sugar for DOM-manipulation + dealing with cross-browser issues.

    jQuery as commonly used leads, in my personal 
    experience, to hard-to-maintain programs. Just
    like Ruby on Rails, or Perl.
Well, I could say the same thing about Java/C# or PHP ... in fact, the shit I had to put up with in those (more structured) platforms is far worse than anything I have seen thus far that was done on top of jQuery / Rails and Perl. And I thought Python/Django had immunity from such problems, until a month ago.

Newsflash: bad developers write bad code.

And yes, I've worked with Perl -- Catalyst and DBIx::Class are pretty good, you should check them out ;-)

Well, you may have a different experience.

I've also noticed a new trend in complex applications, eg JavelinJS and Yahoo's "Minty" mail app, that moves away from jQuery's or YUI's model. They feature a centralized controller/arbiter and a separation of CSS classes and event markup. Instead of jQuery + MVC it's a little of both.

See also http://news.ycombinator.com/item?id=2430271

> jQuery as commonly used leads, in my personal experience, to hard-to-maintain programs.

People using jQuery improperly is not something wrong with jQuery. jQuery is perfectly fine for large web applications, you just need to organize your code properly, with something like a MVC and ORM layer.

One can always argue "you're doing it wrong". People say the same about ror and perl. But in my experience, even with a good mvc and object model, and world-class folks, complex applications in jquery tend to become hard to maintain. I believe part of the reason is the tight coupling of state and events to the DOM.

I'm also very skeptical of the dozen-odd undocumented "extensions" to the selector language. They are useful, but tend to tie you to jQueryisms. I didn't realize for a long time that :first was not valid CSS3.

:first-of-type is valid CSS3, though.

And :first-child is valid CSS2.1.

Undocumented as in "we included it in our 'CSS3-compliant selector engine' but do not mention anywhere that it is not actually part of the CSS3 spec, just something we thought was cool".

http://api.jquery.com/category/selectors/ "Borrowing from CSS 1–3, and then adding its own, jQuery offers a powerful set of tools for matching a set of elements in a document."

Yes, you've found the five-word phase that mentions that there are extensions in the selector engine. There is no documentation on which things are, or are, not, extensions.

Now that we've gone all the way down the pedantry slide, have you anything of value to contribute, or was that it?

You're being disingenuous here. Anybody looking for information about jQuery's selectors will google "jquery selectors" and find that five-word phrase front and center. Or take a look at the jQuery front page and hover over "CSS3 Compliant" to see "Supports CSS 1-3 selectors and more!".

If you want to pick on something that claims compatibility, try Sizzle itself - http://sizzlejs.com/. In that case, you'll find a summary of alterations right at the top of its documentation https://github.com/jquery/sizzle/wiki .

IMHO the most important "clean code" boundary for web apps is a non-enhanced interface (plain old forms). From there, pages can progressively enhance until the cows come home with jquery plugins and complicated interface code, but as long as you know it boils down to a form submission, it's easy to understand what is going on in the application. The form is the model into your web app, and everything else is just sugar.

And whether working on an android app, a QT application in C++ or a jquery based rich client interface, rich client functionality is always somewhat messy in my experience by nature of having many complex interactions in a stateful environment. I certainly don't see using YUI as a silver bullet to alleviate the complexity. As long as it is always clear where the boundaries between the communication between the client code and the server / and its model, you will maintain a clean and maintainable core.

If you want to ditch the idea of progressive enhancement and work directly with a web api to your server, then similar rules apply; as long as it is clear that "this page / widget presents a snazzy interface to update this model" you can remain sane in the organization of your app.

Finally, if you have a super rich interface like Asana, pivotal tracker or google wave where the entire page is presenting many models at once in many forms, then a functional reactive approach may help, using something like backbone or what luna script promises to be. But using a framework like that has its own cost and complexity and IMO is overkill for many of the web apps out there.

I don't see it mentioned very often, but google's closure-library has some really phenomenal patterns for building maintainable javascript. Its worth checking out Michael Bolin's book, Closure: The Definitive Guide, which goes in depth of the Component and Control frameworks.

I've been using the library for 2 or 3 years now, and I am always surprised to see it has such a small community.

Exactly. I see closure as an ambitious effort to make JavaScript a better language for real complicate applications.

It does look like an interesting library. It's weird that the community seems so small.

Here is Michael's blog: http://blog.bolinfest.com/

And the HN discussion from when it was first open sourced: http://news.ycombinator.com/item?id=924426

Compiler : http://code.google.com/closure/compiler/

Library : http://code.google.com/closure/library/ (UI / widgets)

Templates: http://code.google.com/closure/templates/

Here is a video of the talk you refer to: http://jsconfeu.blip.tv/file/4308069/

So, how does one become a good, non-spaghetti-code javascript developer for the web?

I don't really like js so far, but there are just no alternatives in some cases. And my code ends up like those counter examples. Where can learn how to organize it properly?

James Coglan has written a lot [1] about these issues. His series on evented programming [2] is a good place to start.

[1] http://blog.jcoglan.com/

[2] http://blog.jcoglan.com/2010/02/21/events-theyre-not-just-fo...

No alternatives? Coffeescript is always an alternative to js: http://jashkenas.github.com/coffee-script/

Coffeescript "compiles" to JS--so it's not an alternative to using Javascript; just an alternative syntax for writing javascript.

Well, yeah, but you might as well say that JavaScript is just an alternative syntax for writing assembly language or machine code.

Coffeescript is a different language though. It has different grammar, different keywords and so on. It shares the same object model, and it is usually used on compile form.

There are other alternatives as well[1], such as:

- LLVM languages: http://syntensity.blogspot.com/2011/04/emscripten-10.html

- HotRuby: http://hotruby.yukoba.jp/

- Smalltalk: http://clamato.net/

- Haxe: http://haxe.org/

- Mascara: http://www.mascaraengine.com/

And so on. Coffeescript is just closer to javascript than most alternatives. But it is a different language, and a nicer one in my humble opinion.

[1] https://github.com/jashkenas/coffee-script/wiki/List-of-lang...

I disagree that any language that "compiles" into another language can be considered an "alternative." I'm not bashing CoffeeScript; I haven't played with it much and don't know enough about it say anything one way or the other; but at the end of the day, the result is still Javascript.

> how does one become a good, non-spaghetti-code javascript developer for the web?

Just like anything else, it will take time and active effort. Till then, I suggest work with frameworks which help you structure your code. I use backbone.js and I have heard good things about YUI.

> So, how does one become a good, non-spaghetti-code javascript developer for the web?

Like everything else: throw a lot of time at it, and have a desire to make awesome things. Other than explicit feedback on written code, there is no one thing I could tell you to help you write better JavaScript for web browsers.

Use a good webframework http://ukijs.org/

GWT solves it for me while javascript has these problems.

IMHO, now you've got 2 problems.

People at my job call all JavaScript jQuery, it is so annoying. Even more annoying is that their code (jQuery or not) plain sucks

When I use jQuery (MooTools is my lib of choice) I find myself using it in ways that is very unlike the majority of jQuery that is seen around the web.

I absolutely hate the plugin system simply because you cannot easily get the instance of the plugin an refer to it later. To answer this I use function constructors with the module pattern (its easy and doesnt require an extra lib to get going) to create my plugins. Another thing that I do is when I query for a collection of objects, create an array that represents every item in that collection already wrapped with the jQuery object. This may not seem like a big deal, but there is a difference between

    var collection = jQuery('a');
    collection.each(function(i, l){
        var link = jQuery(l);
        link.bind('click', function(){//do suff});

    var collection = jQuery('a'),
        collected = (function(){
            var c = [];
            $.each(collection, function(i, item){
            return c;
this second way allows you to select an item from collected without having to rewrap it with the jquery object. I dont have any data on it, but it seems like rerunning jQuery() with every mouseover/mouseleave/event etc seems like a waste of processing.

Anyway, that is just a few ways that I use jQuery to make javascript a bit easier. These little tricks have the people that I work with thinking that I'm some sort of genius.

Isn't that second code snippet actually creating a jQuery object for each "a" - even if it is never clicked on? Isn't that rather more of a "waste of processing" than the first, where a jQuery object is created in the event handler?

Why wouldn't you write the first one as:

   $("a").click(function() { // do stuff });

if you need to do stuff with a inside of the function, then you have to do $(this), so every time an a in that collection is clicked $() is run.

In my first example I actually took that problem out of the equation by looping through the collection and storing the jQuery'd a as a var accessible via the event closure. However, if you want to reference an element in that collection later in your code, you have to jump though the jQuery selection hoops.

But you are right, sometimes you may not need to have every element in your selection wrapped in the jQuery object and it is up to you to determine which solution to use in a given case. But I do feel that most cases I see devs constantly wrapping $(this) inside of event handlers when they could have made an external reference/collection before hand and used that.


    var as = $('a'),
        collected //using the same method as above;

    as.each(function(i, e){
This is a very rudimentary example and I know that there is a simpler way to accomplish this, but imagine code with multiple collected items who all match up on a 1 to 1 basis collecting the pre-wrapped objects has its advantages.

But wouldn't multiple potentially long loops on initial load have a greater possible impact on user experience than one extra call to $() per event?

Great point. I think that my simplistic example is just that, simplistic. A better solution for huge collections would be to memoize the retrieval of the $() obj with something like

    var memd = {},
        getMem = function(obj){
           var o;
              o = memd[obj];
              o = memd[obj] = $(obj);
           return o;
and call that function instead of calling $() while inside of an event handler (I havent tested this code, but the concept is straight forward)

I don't want to appear snarky, but as you admit yourself ("I dont have any data on it") you don't know if creating a jQuery object is expensive or not (to be fair, I don't know either) - so why all the extra complexity if you don't know whether the thing you are trying to avoid (creating instance of jQuery during event handlers) actually causes problems or not?

Well given that a lot of the "pro" jQuery tips say that one should avoid rerunning the selector in favor of some sort of memoization:

in favor of

    var ele = $('.class');
I would only assume that re-querying with the jQuery object inside of event handlers has the same adverse effects.

Lets say you have a very simple tabbed thing

    //this is code that i've seen around
    var tabs = $('a.tab'),
        containers = $('div.container');
        var index = tabs.indexOf($(this));
        containers.css('display', 'none');
        $(containers[index]).css('display', 'block'); 
vs //this is how id handle a simple tabber var tabs = $('a.tab'), containers = $('div.container'), all_containers = $.map(containers, function(i, c){ return $(c); });

    $.each(all_tabs, function(i, tab){
        var t = $(tab);
        t.bind('click', function(e){
            containers.css('display', 'none');
            all_containers[i].css('display', 'block');
I just feel that the first one, while more concise (has it obvious areas of improvement, but general idea) would wind up being more expensive than the second.

If running the jQuery object isnt too expensive, why is the practice of rerunning the same selector frowned upon?

Interacting with the DOM is what's slow. It's especially slow if the native querySelectorAll method isn't available because any non-trivial selections necessitate iterating over the DOM tree. That's why you don't want to re-query a selection multiple times.

That's also why it's recommended that all selections start with an id. The size of the tree to iterate over can be quickly reduced using the native getElementByID method.

In the case of $(this), the DOM node is already passed to the event handler, so wrapping it in a jQuery object doesn't touch the DOM tree at all. Furthermore, I always cache it (var $this = $(this);) if I'm going to use it more than once.

Also, in your first example, you don't have to rewrap containers[index] in a jQuery object. All the elements in the selection are already wrapped.

> Also, in your first example, you don't have to rewrap containers[index] in a jQuery object. All the elements in the selection are already wrapped.

Really? I think that is the whole point of this long comment thread -- that the elements in a collection arent already wrapped.


This doesnt work unless i wrap a[i] in $()

But like you're saying, it may be fruitless since the dom is the bottleneck and we're bypassing it by already having the element.

Well there's a few problems with that example:

1) You've got a "global" named a and then a local variable (via the argument) inside the each function called "a"...so that really confuses things.

2) a[i] where a is a jQuery object returns an unwrapped DOM element...what you want is .index().

3) What you're doing is sort of roundabout...

Why not:

    var d = $('div'),
        a = $('a');

    a.each(function(i, el){
         d.text(d.text() +' '+ $(this).text() );

Or if you really want to do it your way:

    var d = $('div'),
        a = $('a');

    a.each(function(i, el){
         d.text(d.text() +' '+ a.index(i).text() );

Shouldn't the second one be:

    var d = $('div'),
        a = $('a');

    a.each(function(i, el){
         d.text(d.text() +' '+ a.eq(i).text() );
Using eq(i) rather than index(i)?

I feel like this should have been the first replay to my rant. The nodes are already wrapped in the jQuery object, just need to use eq to access them by index. I've never seen that before, thanks

They actually aren't already wrapped. The .eq() method pulls an element out of the collection and wraps it in a new jQuery object.

you can also pull these out as standard DOM objects if you access as an array, ie. $('a')[0]

Ah yeah, I forgot you had to use .eq().

The selector engine runs right to left so even if you start with an id but end it with an element it will still be an expensive query. I think the key is to think about your selectors and not go overboard because it's easy.

Well, I think I'm going to spend some time tomorrow looking at the jQuery source code to find out what really does happen but what I suspect is that using a selector is going to be a lot more expensive than creating a jQuery instance directly from an element - presumably using a selector means querying the DOM for matching elements (which could be quite complex) rather than simply wrapping a supplied element in a new jQuery object.

So if you do have some complex selector then I can see that avoiding re-running it makes a lot of sense - for DRY as much as efficiency. However, in an event handler you've been handed the element you want to work with and all you are doing is wrapping it in jQuery to make it easier to work with.

Or something like that :-)

Re-running a selector and wrapping an element in the jQuery object aren't even close to the same thing:


Wrapping elements in event handlers is completely fine.

>why is the practice of rerunning the same selector frowned upon?

Rerunning the same selector is frowned upon for (at least) 2 reasons:

1) It can make for more readable code.

Sometimes it makes more sense semantically to have a local variable that describes the role of an element in the particular block of code you are working on, rather than just what selector you are using to get at the element.

Also, it makes the code shorter and less complex, in your example "tabs" is shorter and easier to read than "$('a.tabs')" etc.

2) ...because it's a stupid simple optimization to make.

This goes in general for ANY JS variable that is not in local scope, is the property of an object, or is returned as the result of a function.

It's so easy to just cache it as a local variable, you should probably just do that once you are accessing it a few times.

Even that has the whiff of premature optimization, but it's so easy and has such a low impact (or even improvement) on readability, that it's no big deal.

What you're talking about is much harder to justify imho.

Re-running the same selector is an instance where you are re-running a function that will definitely return the same result that you just got.

Effectively it's the same as

    function get5(){ return 5; };
    var x = 4 + get5();
    var y = 35 + get5();

...etc etc...so obviously it's better to just cache the return value and save the work of running a function.

It's hard to say because your examples aren't entirely clear to me, but I don't think your version as is is any better, perhaps even worse in some respects.

$('a.tab') returns A jQuery object that has a context that is a collection of DOM elements.

Your map function (which has the arguments reversed fyi) return's an array of jQuery objects (plural); each with a context of a single DOM element.

So you're creating a bunch of new instances of jQuery objects to possibly save an insignificant amount of context lookup time (getting the context of a jQuery object is not as heavy as selector lookup).

Again in the each you're creating a new jQuery object for each tab element, even though it was already in one. A jQuery object which will stick around via the closure.

So this is all to save looking up the index each click event for the tab (btw, something like $(this).index() would probably be cleaner) which may or may not be worth it.

I can see where you're going, and think you've got the right idea, but I also think what you use really depends on the situation.

I would say just write clean and idiomatic code first...that should be the default.... and then if you hit problems you can start optimizing based on the situation.

If looking up the index and context each click really is a problem (could be in some situations) you could find a solution based on the situation using strategies like event delegation, strategic naming, caching the index, associating them in a data structure of some kind, of any combination thereof.

Thanks for the reply, I get what you're saying and agree to an extent, the question was rhetorical though.

> Your map function (which has the arguments reversed fyi)

Oh god, jquery is php.

I guess it's just bit of cpu for memory trade-off

>>allows you to select an item from collected without having to rewrap it with the jquery object

I think the following does the same thing:

    var collected = $('a').map(function(element) {return $(element)})

Or even simpler:

    var collected = $('a').map($)
However, map as defined on jQuery objects takes a function that takes the index as the first argument, and the element as the second argument:


So, what you actually want is:

    var collected = $('a').map(function(index, element) {return $(element)})
However, jQuery.map has the element as the first argument, and the index as the second argument:


I would consider this to be the more intuitive way round, although I'd prefer it if both maps were consistent. So, you could write:

    var collected = $.map($('a'), $)
which strikes me as the neatest version.

Nice, I didnt know that jQuery had map. Thanks.

Cant edit, but my second argument, creating an array containing already jQuery wrapped elements is null.

There is a method called .eq() that allows you to select from the collection and it returns the element wrapped for you.

I left a job where I'd built a simple UI to a complex back-end using jQuery. A former co-worker told me the guy who'd taken over that project kept complaining that he didn't understand "all this JSON" in the app.

Friend: "Can I see some of the JSON?" In-over-his-head Developer: "Sure, here." Friend: "That's not JSON, that's jQuery." Dev: "Whatever, it's the same thing." Friend: "No it's not and you thinking it is, is the real problem here."

Hey! That's exactly how my jQuery code looks! I think I just got seduced by all the closurey goodness that comes with Javascript (my day-job languages don't let me do that.)

I'm not going to ask how to write good code, but I think this is a fair question: can someone point to a coding standard / style guideline for Javascript + jQuery?

E.g., when to choose a single-use named function over an anonymous function? When to bind jQuery results to variables vs. go crazy with chaining? Any advice on good selector practices? Good html naming conventions?

I'd love to see all that stuff documented in one place. It must be out there somewhere.

> can someone point to a coding standard / style guideline for Javascript + jQuery?

backbone.js is good. That gives you a fair idea about structuring your application. If you webapp is designed in a RESTful manner, backbone.js maps quite nicely to your backend.

I think the most important, and often violated principle is to keep model and presentation code separated. If your widget has any kind of even slightly complex logic, don't rely on the dom to be your model, or you'll get into a mess quickly. The dom (and thus jquery) is presentation (controller/view). Create separate objects for your model and have your controller code (even handlers) update this and your view be updated from it.

I know that it is extremely simply to write spaghetti code in just about any language, using any supporting library, but I'd say check out some of the stuff that the MooTools guys are doing. I come back simply amazed at some of the things that they're doing. Check Company http://code.keetology.com/company/ its a different approach to solving the same problem(s) as backbone

I was hoping for a Backbone.js mention. A tool like that will get you a long way in structuring your frontend code.

Backbone.js came out just a couple of weeks before I gave this talk in October 2010, and I just hadn't had time to look at it enough to feel comfortable mentioning it. It is definitely a powerful tool for bringing structure to an application, and I'd certainly mention it if I were to give the talk today.

I don't like presentations like this. What suggestions or solutions were offered? Perhaps the audio mentioned some good resources to use to learn how to properly architect a complex, Javascript/JQuery heavy application, or perhaps I just missed it in the slides, but to me it just seemed like a rant. Sure it's identifying an issue but it would be a whole lot more useful if it gave some links to books/articles/etc with details on how to layout your code in a maintainable manner.

I'd encourage you to bear in mind the original audience of the presentation: the very small number of experienced JavaScript developers who managed to obtain a ticket to the 2010 JSConf.eu in Berlin.

The goal of this presentation wasn't to teach people how to write good JavaScript -- many of the people in the room that day can and do write circles around me. Rather, the goal was to urge them, the experienced JS devs who are inventing the answers to these questions, to take seriously the need for creating exactly the information you point out to be lacking, and to be intellectually rigorous and honest in discussions of various solutions.

I'd suggest that you pay extra attention to the presentation starting at slide 40, and especially to what I said on slide 60: "Sharing what we know is as important as making new things." That, in a nutshell, was the message I sought to convey to the audience in October.

jQuery is popular because you don't need any programming experience to be productive. I was introduced to jQuery by our in-house web designer like 3 years ago because he used it and really liked it. He spoke HTML, the DOM and CSS and so does jQuery. And there are far more HTML/CSS literate people doing Javascript than there are CS-educated software engineers doing Javascript. In fact most software engineers I know don't know crap about Javascript. Thankfully I read "Javascript: The Good Parts" and have a much better appreciation for the language.

I also like jQuery as well. If you're doing simple DOM manipulation, AJAX and light javascript work it's hard to do any better. But I think there are superior choices for some more heavy lifting JS projects.

Nice presentation, I am not sure about most people here but I started using jQuery because the documentation was excellent, easy to navigate, with lots of examples. Hence trying it out was simple and I got hooked.

At that time IMO the other libraries apart from YUI, did not seem to have everything in place to learn how to use them quickly. I was put off YUI at the time because it seemed incredibly verbose, this has since been improved.

Also I think a distinction can be made between using jQuery and using the widget factory which does allow for more modular maintainable code.

Maybe the MVC design pattern doesn't work so well with jQuery in the view, acting as a controller and also for display logic.

Surely there is a design pattern that does not try to shoehorn AJAX via jQuery into what was once an MVC pattern?

MVC for webapps was around long before AJAX, yet the design pattern remained the same, after the widespread introduction of AJAX in webapps. Until very recently, there has been little traction in an 'evolved' design pattern, incorporating what the js is doing.

About time someone came out and said this, good job.

Said what? Did I miss it? He seemed to just stop midway.

He implied there was a problem, showed some code, but never showed where the problem lies or what it was, and certainly never mentioned any solution.

All I got was some vague "this isn't pretty" vibes.

The problem is, "this isn't pretty" is pretty much all we've got. There is very little information on how to organize javascript apps, or how to write javascript at all. Nobody knows the solution yet.

Most of the stuff on javascript programming is bullshit. "Javascript, The Good Parts" from Douglas Crockford is good. But it is only a start, we need more of that. The majority of books is trying to apply OOP design patterns or plainly translate GoF. I'm sure we can do better now.

'He' is a she: Rebecca Murphey


I can't speak to what else you missed or didn't miss, but you do seem to have missed that he is a she, so ...

doesn't change the original point

Since no particular solutions were offered in the talk...

HN: What are the best technologies for writing large JS apps?

I have experience writing Closure (http://code.google.com/closure/) and its structure is pretty scalable, but it feels like so much effort to do simple things. Styling the widgets is a pain. Making a custom widget (extending goog.ui.Component) is surprisingly difficult to get right for even simple extensions.

After all that, I still think it's probably better to develop in that over jQuery -- at least you end up with a straightforward, modular, testable structure at the end of the day.

Is there something better? backbone?

Applications are open for YC Summer 2019

Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact