JavaScript Namespacing

Posted by Jack Hsu Wed, 24 Mar 2010 14:48:00 GMT

One of the first things you learn programming in JavaScript is, "Global variables are evil." This is especially true when writing a JavaScript library, but I’d take that advise even otherwise to avoid unnecessary headaches.

As an avid jQuery user, one thing I do in almost every project is define a namespace function on the jQuery object.

jQuery.namespace = function(ns, obj) {
    var ns = ns.split('.'), 
        p = window,
        i;
    for(i=0; i<ns.length; i++) 
        p = p[ns[i]] = p[ns[i]] || {};
    if (obj) 
        jQuery.extend(p, jQuery.isFunction(obj) ? obj(p) : obj);
};
 

This function will take in either an object or a function that takes in an object, then create the namespace or extend it if it exists.

// Example 1
$.namespace('foo.bar', {
    myVar: 1, myOtherVar: 2, someFunction: function() { alert(this.myVar + ',' + this.myOtherVar); }
});
foo.bar.someFunction();
//--> alerts "1,2"

// Example 2
$.namespace('faz', { baz: { a: 1, b: 2 } });
$.namespace('faz.baz', function(old /* previous namespace */) {
    old.a = 'new value'; // change previous assignment of a
    old.printMe = function() { alert(old.a + ',' + old.b); };
});
faz.baz.printMe();
//--> alerts "new value,2"

The second example shows a case where an function is passed instead of an object. This is useful for many reasons which I won’t get into… actually you can read a great post here about JavaScript module patterns.

And when jQuery isn’t being used on a project, the following does the exact same.

function namespace(ns, obj) {
    var ns = ns.split('.'), 
        p = window,
        i, k;
    for(i=0; i<ns.length; i++) 
        p = p[ns[i]] = p[ns[i]] || {};
    if (obj) {
        obj = obj instanceof Function ? obj(p) : obj;
        for (k in obj) {
            if (obj.hasOwnProperty(k))
                p[k] = obj[k];
        }
    }
}
 

Not all jQuery selectors are created equal 2

Posted by Jack Hsu Thu, 24 Dec 2009 14:36:00 GMT

The good thing about JavaScript libraries such as jQuery is that developers can focus on functionality without having to worry too much about cross-browser compatibility. However, often times it is still very useful to know why happens behind the abstractions.

The most used feature in jQuery is the CSS selector. Instead of selecting elements using pure DOM (e.g. document.getElementById(‘myId’)), you’re able to use jQuery’s CSS selector (e.g. $(‘#myId’)). This makes life much, much easier.

There are cases, however, where not knowing what happens behind the scenes can lead to poor implementations, causing big performance hits. One such case is the class selector (e.g. $(‘.someClass’)).

The reason why class selector is slow is because it has to go through the entire DOM to find those elements. Of course, some browsers like Firefox 3+ has native support for document.getElementsByClassName. And as John Resig analyzed, the native method is much faster than the next fastest implementation (XPath). But if you want your applications to run as fast as possible on as many browsers as possible, it’s better to avoid the class selector all-together (at least for now).

What you can do instead is to use the next fastest selector (behind ID selector), the tag name selector.

So instead of doing $(‘.someClass’), use $(‘div.someClass’), or whichever HTML tag name you want to use. This selector is faster because instead of checking the entire DOM, now it only needs to check against elements with that particular tag name. That is, it first does a document.getElementsByTagName(‘div’), then iterates through that list.

Or why not make it even faster by specifying an ancestor element by its ID? (e.g. $(‘#ancestor div.someClass’))

The thing to keep in mind is, no matter what abstractions come about, it’s still a very good idea to understand what happens underneath the hood. :)