Object-oriented JavaScript follow up part 2: Technical

Published 22:12 on 28 October, 2010

Following on from part 1 of my follow-up to “Object-oriented JavaScript”, part 2 provides a technical update to some of the theories and examples.

Without further a-do, let’s jump in with the technical stuff:

A quick note on variable declaration

The var declaration allows you to chain definitions in a comma separated list; what’s more that list can reference variables declared earlier in the same list.

Take this code as an example:

var el = document.getElementById(my-element);
var elWidth = el.offsetWidth;
var elHeight = el.offsetHeight;
var elArea = elWidth * elHeight;

This could alternatively be written like so:

var el = document.getElementById(my-element),
    elWidth = el.offsetWidth,
    elHeight = el.offsetHeight,
    elArea = elWidth * elHeight;

Personally, I prefer the latter method simply because it keeps my var declarations in one place (where possible) without endless repetition of the var keyword. However, this is simply a minor note on coding style, rather than something that can improve the operation of your code.

Understanding object-oriented scope

As any experienced JavaScript coder knows, JavaScript is functionally scoped; this means any variables created within an object or function are only available within that object or function.

Simple, right?

Well no, there are actually a couple of complications to this behaviour that you should really understand:

Passing by reference

When passing arguments in JavaScript, it’s not immediately clear how those arguments are being handled internally. In fact, it is entirely dependant on the data-type of those arguments.

When passing arguments of type Number, String, or Boolean, JavaScript will pass them in by value. This means that the value stored in the argument will actually be a copy of the original value:

function accidentalFall(count) {
    count = count - 1; // Remove one
}

var greenBottles = 10;

alert(greenBottles); // greenBottles is 10

accidentalFall(greenBottles); // Pass by value

alert(greenBottles); // greenBottles still 10

Passing in an object, however, passes the argument by reference. This means that, within the function, the argument is not a copy, but a reference—or link, if you like—to the original object. This means any members of that object are available within our function, and any changes to the object passed as an argument will be reflected outside of the scope of the function.

Actually, the way JavaScript handles references is another blog article in itself. Watch this space.

Here’s our example again:

function accidentalFall(obj) {
    obj.count = obj.count - 1; // Remove one
}

var greenBottles = {
    count: 10
};

alert(greenBottles.count); // 10

accidentalFall(greenBottles); // Pass by reference

alert(greenBottles.count); // 9

This is a subtle difference, but one, I think you’ll agree, that is important to understand.

The this special operator

The this operator can be used to obtain a reference to the current context object and allows properties and methods within that execution context to be referenced. The context object can be considered a “hidden” parameter that is passed to any function.

There are four ways the context is made available to a function:

Implicitly with a method

var myObject.method = function(arg1, arg2) {
    // Context here is myObject, and has been passed
    // implicitly.
}

Implicitly with new

var myConstructor = function(arg1, arg2) {
    // Here we have a new anonymous context
    // understandable as the instance…
}
// …so the context here will be myObj
var myObj = new myConstructor(arg1, arg2);

Explicitly with Function.call

var myObject.method = function(arg1, arg2) {
    // Implicit context is myObject
}
// Explicitly force context to anotherObject
myObject.method.call(anotherObject, arg1, arg2);

Explicitly with Function.apply

var myObject.method = function(arg1, arg2) {
    // Implicit context is myObject
}
// Explicitly force context to anotherObject
myObject.method.apply(anotherObject, [arg1, arg2]);

In general, JavaScript developers tend to rely on implicit context passing rather than explicit. However, there is one situation where this reliance falls down…

A common problem

When registering event handlers against DOM nodes in JavaScript, the this context no longer references the method’s parent object, but rather the DOM node to which the event handler is registered.

The easiest way around this is to make sure the reference to the context object originally stored in this is maintained before defining the event handler:

var widget.init = function () {
    var myButton = document.getElementById(my-button),
        counter = 0,
        that = this;

    myButton.onClick = function(event) {
        that.counter++;
        this.innerHTML = Clicked!;
    }
}

Further to this, according to Douglas Crockford, there is an error in the ECMAScript spec. that causes this to be set incorrectly for inner functions; something that he discusses in his article Private Members in JavaScript:

function Container(param) {
    function dec() {
        if (secret > 0) {
            secret -= 1;
            return true;
        } else {
            return false;
        }
    }

    this.member = param;
    var secret = 3;
    var that = this;

    this.service = function () {
        if (dec()) {
            return that.member;
        } else {
            return null;
        }
    };
}

Now, the "var that = this" technique is certainly a bone of contention amongst members of the JavaScript community, but I’m firmly on the fence in the whole discussion. Certainly my second example could be solved with a complex network of Function.call and Function.apply instead of that.member, but my first example would be somewhat more difficult.

Personally, I feel if Doug Crockford—a developer with many years more experience and infinitely more JS knowledge than myself—says it’s ok, then I’m fine with it.

Garbage collection

As JavaScript is a scripting language, it implicitly allocates memory for objects, strings, variables, and so on as it runs. Garbage collection is the process by which the JavaScript engine detects when those pieces of memory are no longer reachable—that is, they could not possibly ever be used again—and reclaims the memory.

The ECMAScript specification (of which JavaScript is an implementation) doesn’t include a definition on how a JS engine should handle garbage collection, so although each JavaScript engine includes garbage collection—memory usage would quickly snowball if they didn’t—they all handle it somewhat differently.

Some engines are better than others; Google’s V8 is exceptionally good, where as the IE JScript engine is notoriously bad (often resulting in memory leaks).

Nested functions and closures

JavaScript allows the nesting of functions, creating nested scope blocks that inherit scope from their parents all the way up to the global scope.

Take this code for example (there are much better ways of doing this; this method is only in the interests of illustration):

function appendList(list, itemPrefix) {
    var getListItem = function(x) {
        return document.getElementById(itemPrefix + x);
    }

    for (var i = 0, j = list.length; i < j; i++) {
        getListItem(i).innerHtml +=  [done];
    }
}

In the above example getListItem is a nested function within appendList. This means it inherits everything within the scope of appendList. As a result of this, the inner function is able to make use of the itemPrefix parameter that is passed to its parent without it needing to be passed in as another parameter on getListItem.

When JS automatically garbage collects the appendList function, it will find no external references to the getListItem function and will garbage collect that as well.

This is a useful feature of JavaScript, and allows for fairly advanced lambda functions (anonymous functions), as well as providing a useful tool for namespacing library functions.

However, if, upon garbage collection, JavaScript finds an external reference to a nested function, it creates a closure of scope; thus maintaining access to all the variables required within the scope of that function.

This is known as a closure.

Common usage of closures

The most common occurrence of a closure in JavaScript is when declaring event callbacks. This is simply due to the fact that the callback function is referenced within the event listener once registered.

However, it’s important to understand that many modern libraries, plugin architectures, and plugins themselves also make use of closures, and understanding how they use them can mean the difference between controlled and uncontrolled memory usage.

Invisible pitfalls are invisible

It’s obvious when you think about it, but all closures have a potentially high memory imprint as they are maintaining much more than just their constituent parts. What’s more, because of their inherent avoidance of garbage collection, they are maintained until they are manually destroyed either by the code, or by a page refresh.

Prototypal inheritance

I did discuss prototypal inheritance in my original Object-Oriented Javascript article, however I just want to go into a little more detail here.

In a prototypal system, objects are supposed to inherit from objects; unlike in a classical inheritance system where classes inherit from classes and instantiate objects. JavaScript has no class (pun intended).

Prototypal inheritance is actually simpler than classical inheritance once you get your head around it. You don’t need to define classification, so your code is smaller and less redundant since objects inherit from other more general objects. It is a model of differential inheritance; i.e. each level of inheritance only adds the differences with its parent.

Unfortunately, JavaScript is a bit confused about its prototypal nature, and wants to fit in with the other scripting languages by pretending to like The Beatles and by making itself more attractive to classically trained programmers by introducing the new operator.

This means that:

new myConstructor();

produces an object that inherits from myConstructor.prototype.

This indirection means that JavaScript actually has a pretty ugly constructor pattern and most new JavaScript developers never really get to grips with the inheritance model at all.

However, all that has changed with the all singing, all dancing advent of JavaScript 1.8.5 (The New Shit™), which introduces the Object.create method:

var human = {
    legs: 2,
    arms: 2
};

var tim = Object.create(human, {
    tall: true,
    fat: true,
    overInflatedSenseOfSelfImportance: true
});

Mmm tasty, but since JS 1.8.5 only seems to be implemented in Firefox 4 (still in beta), don’t get all excited just yet.

If you want something similar in your own code, you can implement the following for a similar approach (and still kiss goodbye to ever having to use the new operator again):

if (typeof Object.inherits !== 'function') {
    Object.inherits = function(parent, child) {
        function temp() {};
        temp.prototype = parent.prototype;
        child.super_ = parent.prototype;
        child.prototype = new temp();
        child.prototype.constructor = child;
    };
}

Object.inherits(parentConstructor, childConstructor);

What’s more, this DIY version will allow you access to any superclass’ implementations of a particular method like so:

childConstructor.prototype.foo = function(a) {
    // Here’s some of that scope correction we discussed
    // earlier…
    childConstructor.super_.foo.call(this, a);

    // Other code
};

This code is a mix of the goog.inherits function—included in the Closure library—and the Object.create outline by Crockford in his article on prototypal inheritance.

JavaScript design patterns

Taking all this into account, we can start developing some incredibly useful design patterns that make use of prototypal inheritance, closures, and JavaScripts nuances of scope.

In fact, several have already been developed within the JavaScript community:

JavaScript namespacing

To avoid the perils of globally scoped variables and functions, it is advisable to create a single global object for the purposes of namespacing the rest of your code. This is relatively simple to achieve:

var NEF = window.NEF || {};

This command tests for the existence of a NEF object at the global scope, and if evaluated to true, returns that object. Otherwise, it creates a new object using the object literal syntax.

You may now assign any further variables or modules to your namespace:

NEF.myAttribute = foo;
NEF.myFunction = function() {
    
};

Module pattern

The JavaScript module pattern was first proposed by Doug Crockford as a means of enforcing public and private object members through the use of closures.

My preferred variation on the pattern is such:

NEF.Module = function() {
    // Private members
    var privateAttribute;

    function privateMethod() {
        alert('Private method called.');
    }

    var pub = {
        // Public members
        publicAttribute: true,

        publicMethod: function() {
            // Private members are in scope here

            privateMethod();

            // Public members are addressable through the 'pub' object.

            pub.publicAttribute = false;
        }
    }

    return pub;
}();

This method simple uses a closure to maintain private variables in the scope of the returned pub object. The trick of this technique is the use of the (), right at the end of the code, after the parent function definition, which causes the function to run immediately and return the pub object.

jQuery plugins

The jQuery plugin architecture also makes use of closures to do something quite similar to the Module Pattern above. However, jQuery plugins are specifically namespaced to the jQuery object itself:

(function($) {
    // Private members
    var debugMode = false;

    function debug(msg) {
        if (!debugMode) { return; }
        if (window.console && window.console.log){
            window.console.log(msg);
        } else {
            alert(msg);
        }
    }

    $.fn.extend({
        myPlugIn: function(config) {
            var defaults = {
                
            };

            if (config) {
                $.extend(defaults, config);
            }

            this.each(function() {

            });

            return this;
        },

        publicMethod: function() {
            
        }
    });
})(jQuery);

Alternatively, should you wish to only include a single public method, you can avoid jQuery.fn.extend by instead making use of jQuery.fn for definition:

(function($) {
    // Private members
    var debugMode = false;

    function debug(msg) {
        if(debugMode && window.console && window.console.log){
            window.console.log(msg);
        } else {
            alert(msg);
        }
    }

    $.fn.myPlugIn = function(config) {
        var defaults = {
            
        };

        if (config) {
            $.extend(defaults, config);
        }

        this.each(function() {

        });

        return this;
    };
})(jQuery);

In this code we can see that jQuery is passed to an anonymous function, that is run immediately, as the parameter $. The anonymous function provides a scope block for the plug-in code, thus preventing potential headaches from variable naming clashes across shared code. The plug-in functions themselves are then created as closures so that they have access to the private variables and functions within that outer anonymous function. These plug-in variables are then bound to the passed in jQuery instance $ using jQuery’s own built in extension functions.

This is actually quite a clever use of closures, although it does have the potential for memory leaks and excessive memory usage if variables and references aren’t kept in check. With that in mind, it’s often a very good idea to profile your jQuery plugins to understand what might need tidying up.

Custom events

Most modern JavaScript libraries include a mechanism for defining your own custom events. A custom event is merely a bespoke event, defined in your code, that other event-handler functions may be bound to. This custom event may then be triggered by you at any given point of execution in the code.

The custom event architecture is an implementation of the Observer Pattern, in which an object maintains a list of dependant “observers” which it notifies automatically of any state changes. In JavaScript, the object maintaining the list is our event, and the “observers” are the event handlers.

Using custom events in your own code provides a useful binding for other developers’ code. The event itself is loosely coupled to the event handlers, thus, additional event handlers can be added or removed by third-party code.

For more information on custom events, I’d recommend having a look at the documentation for the library of your choice. Here are few links:

Summary

So that’s the technical addendum to my 2006 post. Hopefully, that should serve to bring the article up to date, and correct a few of my previous errors. As always, comments and corrections are welcome via the comment form below.

Originally I had intended posting this article in two parts, however, it has continued to grow even as I write it. For this reason, the third and final part of this follow-up series will look at what’s on the horizon for JavaScript development, including how GoogleBot deals with JavaScript, the importance of supporting a core experience (where JavaScript is unavailable), server-side JavaScript, and architecting JavaScript applications.