Closure Exposure

These days people are becoming more aware that you can write real object oriented code in Javascript. Even though the language doesn’t support classes with private members directly, you can achieve the same thing quite easily using closures.

function MyClass() {
    // Private members
    var internalCounter = 0;
    var somePrivateFunction = function(input) {
        return input + " foo!";
    };

    // Public members
    this.getCounter = function() {
        return internalCounter;
    };
    this.increment = function() {
        internalCounter++;
    };
}

Here, the first two members are effectively private, as they can only be accessed from functions declared within MyClass.

This is all well and good, and makes me feel much better when I have to write Javascript, but if you’re a serious Javascript developer you’ll want to unit test your code as you go along. How are you going to test those pesky private variables and functions?

Dude, let me in!

The problem is, you can’t break into a closure because it’s enforced by the language. You can try as hard as you like, but there’s no way you’re getting access to somePrivateFunction() without modifying the code of MyClass. This is a good thing - it means the private functions are truly encapsulated. But it does make testing a bit difficult.

One trick I like is to add the following line to the end of the class constructor.

this.debug = function(code) { return eval(code); };

Because of the way the eval command works, this now means that any of the private members can be extracted from within the class. For example, we can now write a unit test for somePrivateFunction. (This is a QUnit test, which is the test framework jQuery uses).

test("somePrivateFunction", function() {
    var my = new MyClass();

    // extract the private function from the closure
    var somePrivateFunction = my.debug("somePrivateFunction");

    // call the function
    equals(somePrivateFunction("hello"), "hello foo!");
});

We have slightly polluted the original class with this extra line. If it worries you, the ‘debug’ lines can easily be stripped out before the code goes into production.