jQuery camouflaging javascript complexities

I’ve been writing javascript for awhile and when I was first introduced to jQuery it was such a great experience. Finally DOM manipulation in javascript didn’t suck. As the framework progressed it added more and more convenience that started to hide a lot of the complexity of javascript.

It can be argued that hiding these complexities is a good thing, javascript gives you more than enough rope to hang yourself and shortening that rope will increase developer productivity, reduce errors and lead to an overall better development experience. Unfortunately it seems there is such a reliance on frameworks these days that many of the basics of javascript never actually are understood by many developers.

One of these basics is closures within a loop. This often comes up in event binding when you iterate over a list of items and attach an event to each item.

// vanilla javascript way
var dataItems = ['a','b']
var i = dataItems.length;
while(i) // using descending while loop for efficiency
{
   var ele = createElement('div');
   ele.onclick  = function(dataItem){
           return function(event)
           {
               // do something with dataItem
               alert(dataItem);
           }
   }(dataItems[i-1]);
    i--;
}

This is a standard way of creating a scope containing the variable you want to have available in the event handler that isn’t tied to the loop iteration variable. If we didn’t wrap the function to bind to the click event in another closure every alert would come up as ‘b’.

jQuery for a long period of time required you to do something similar when using their own event binding model.

// jquery < 1.4.3 way
var dataItems = ['a','b']
var i = dataItems.length;
while(i) // using descending while loop for efficiency
{
   var ele = $(createElement('div'));
   ele.bind(function(dataItem){
           return function(event)
           {
               // do something with dataItem
               alert(dataItem);
           }
       }(dataItems[i-1])
   );
    i--;
}

In the above example you still have to understand closures in order to make your code work. Developers still learn the lesson of why their closure is pointing to the last element in the array and still get that “a ha” moment.

In jQuery 1.4.3 they added the ability to pass data arguments in the bind function alleviating the need to create an additional closure to pass the correct arguments. This is a great feature in a framework it cleans up code significantly.

// jquery >= 1.4.3 way 
var dataItems = ['a','b']
var i = dataItems.length;
while(i) // using descending while loop for efficiency
{
   var ele = $(createElement('div'));
   var dataItem = dataItems[i-1];
   ele.bind({'dataItem':dataItem},function(event){
               // do something with dataItem
               alert(event.data.dataItem);
           } 
   );
    i--;
}

The downside is this method completely hides a fundamental language feature from the user. This has the potential to lead to a group of new developers that really don’t understand javascript, only jQuery. This is a bit worrying since jQuery, while being a good framework, isn’t going to be the best tool for the job everywhere.

The recent ecobee android application is good example. It is written as a html5 application and I quickly realized the performance impact of jQuery on a mobile device is enough to degrade the experience significantly on underpowered devices (the sort of android device that you get for free with a 2 year contract).

Javascript isn’t going anywhere and is becoming more important in the land of cross platform mobile applications. This doesn’t mean that developers shouldn’t understand how the language they are using works under the fancy framework they’ve chosen. Maybe it doesn’t matter in 99% of cases and I’m just being pedantic but understanding closures seems like a fundamental concept in javascript and it is worrying that so many don’t understand why their event assigning loop is “broken”.

Leave a Reply