For a few years now I've been writing scripts using jQuery and for years I thought it's the limit of a well-designed architecture of a JavaScript application or at least some JavaScript enhancements for a static content. After all it was so much better (actually it still is ) then old-style JavaScript with events handlers attached as a html attribute. Then backbone came up and I've discovered that there are plenty of JavaScript frameworks that put in to practice ideas that I've been already using in server side languages. Even jQuery turns to be an object with a set of methods rather than bunch of loosely coupled functions.

So I had this growing script`s file with several jQuery`s plug-ins calls, events bindings, events delegations, asynchronous calls to server side APIs with promises or with nested success functions, list of functions used multiple times and sub/pub design pattern in background. More than 1000 lines of code in total plus the perspective of adding another few hundred in the nearest future. All of those written on 2 years period, which means that part of code it's quite nice but the most code... I prefer not to touch it.

I'm not sure if it's a good code and a good situation to use something like backbone or maybe I need just some experience to rewrite all I have using heavy-duty tools. Nevertheless when I've lately started working on a new module I decided to write it purely in JavaScript. I've started with standard messy code I used to do many times before, but at some point I refactored a few hundreds lines of code making it more readable and manageable. Inspiration came from todomvc - a side at which we can compare the same application written in various frameworks.

So how to improve jQuery code? Basing on the todomvc experience I think that the first step is to split the code into objects. It may be a one object if that makes a sense for you and it's completely fine to make another objects of code that is already in the application at any given time. Some parts of application can evolve or grow surprisingly so it's necessary to keep track of them. Basic code structure can look like this:

    var App = {
                    init: function() {
                            this.cacheElements();
                            this.bindEvents();
                            this.render();
                    },
                    cacheElements: function() {},
                    bindEvents: function() {},
                    render: function() {}
            };

    App.init();

Probably you are already caching jQuery selectors. CacheElements method is a appropriate place to do it. BindEvents() is a place for all event binding and render() can be used for creating view or adapting a view to the client's screen resolution. If your application need initial data I can be retrieved form getData() method called in a init() method which is called after script is loaded. I strongly recommend you to see and analyze this: todomvc jQuery example.

Refactoring pitfalls

Although there are many advantages of making your code more object oriented you must avoid fallacy that refactoring will be limited to coping and pasting code that you have. If you do it this way it'll probably break and if not you probably didn't improve your app as much as you could.

When you're creating a caching method create cache variables only for id elements, unless you are doing a lot of manipulations on classes or tags initially (before adding new elements) or you are sure that no new elements will be added. In other case you may wonder why your newly created item have no event handlers but other elements with the same class have. It's because cache object was created at the time application was initialized and it's not updated. It's important to remember about that.

Second problem you may encounter rewriting event bindings. Maybe it's my rather than general problem and it accrued because my code refactoring coincided with changing simple event handlers into event delegation. Event delegation works much better then attaching handlers for every newly created object, so I've take a chance and rebuild this part of code. Nevertheless after I've finally finished unifying all of my events it turned out that standard events work, but some plug-in calls don't and some does. Not working may be here a little misleading, because they were working but much more that is needed. They've been reattaching every time delegation took place. After spending a few hours on research I decided to use delegation only on those plug-ins that work. The rest will work as before so they will be called on the initialization and on new element creation.

Last major problem I had to deal with was change of keyword "this" meaning in a new method context. Once you are defining some element as this.$elem but when you are using it in a App's method you are doing this by App.$elem. Another related problem is splitting complex plugins such as jQuery's UI autocomplete into smaller methods and wrapping it with an object. In object's method "this" will have no relation to autocomplete object any more so if you need original object (and definitely you will) you will have to pass it as a parameter.