Revealing Prototype Pattern - Techniques, Strategies and Patterns for Structuring JavaScript Code

Using the JavaScript Revealing Prototype Pattern

imageThis is the 4th post in a series on techniques, strategies and patterns for writing JavaScript code. In my previous post I discussed the Revealing Module Pattern – one of my favorite JavaScript patterns. If you like the features offered by the Revealing Module Pattern but want to take advantage of JavaScript’s prototype functionality and the benefits it offers, the Revealing Prototype Pattern may be what you need. It offers the benefits of the Revealing Module Pattern but also provides a way to share function implementations across object instances through prototyping. The pattern is a combination of the Prototype Pattern and Revealing Module Pattern.

As a quick review, I showed the following code in the first post. The code simply lists all functions directly with no encapsulation and defines several global variables. While the code works fine this way, I’ll examine how we can restructure it to follow the Revealing Prototype Pattern.

window.onload = function () {
    eqCtl = document.getElementById('eq');
    currNumberCtl = document.getElementById('currNumber');
};

var eqCtl,
    currNumberCtl,
    operator,
    operatorSet = false,
    equalsPressed = false,
    lastNumber = null;

function add(x,y) {
    return x + y;
}

function subtract(x, y) {
    return x - y;
}

function multiply(x, y) {
    return x * y;
}

function divide(x, y) {
    if (y == 0) {
        alert("Can't divide by 0");
        return 0;
    }
    return x / y;
}
     
function setVal(val) {
    currNumberCtl.innerHTML = val;
}
        
function setEquation(val) {
    eqCtl.innerHTML = val;
}
        
function clearNumbers() {
    lastNumber = null;
    equalsPressed = operatorSet = false;
    setVal('0');
    setEquation('');
}

function setOperator(newOperator) {
    if (newOperator == '=') {
        equalsPressed = true;
        calculate();
        setEquation('');
        return;
    }
            
    //Handle case where = was pressed
    //followed by an operator (+, -, *, /)
    if (!equalsPressed) calculate();
    equalsPressed = false;
    operator = newOperator;
    operatorSet = true;
    lastNumber = parseFloat(currNumberCtl.innerHTML);
    var eqText = (eqCtl.innerHTML == '') ? 
        lastNumber + ' ' + operator + ' ' : 
        eqCtl.innerHTML + ' ' + operator + ' ';
    setEquation(eqText);
}

function numberClick(e) {
    var button = (e.target) ? e.target : e.srcElement;
    if (operatorSet == true || currNumberCtl.innerHTML == '0') {
        setVal('');
        operatorSet = false;            
    }
    setVal(currNumberCtl.innerHTML + button.innerHTML);
    setEquation(eqCtl.innerHTML + button.innerHTML);
}

function calculate() {
    if (!operator || lastNumber == null) return;
    var currNumber = parseFloat(currNumberCtl.innerHTML),
        newVal = 0;
    //eval() would've made this a whole lot simpler
    //but didn't want to use it in favor of a more
    //"robust" set of methods to demo patterns
    switch (operator) {
        case '+':
            newVal = add(lastNumber, currNumber);
            break;
        case '-':
            newVal = subtract(lastNumber, currNumber);
            break;
        case '*':
            newVal = multiply(lastNumber, currNumber);
            break;
        case '/':
            newVal = divide(lastNumber, currNumber);
            break;
    }
    setVal(newVal);
    lastNumber = newVal;
}


To start using the Revealing Prototype Pattern you’ll first create a constructor as with the Prototype Pattern and define any variables that are unique to an object instance:

 

var Calculator = function (cn, eq) {
    this.currNumberCtl = cn;
    this.eqCtl = eq;
};


This example allows two DOM elements to be passed in which are stored in the currNumberCtl and eqCtl variables. Once the constructor is created you can define the prototype. Unlike the Prototype Pattern which assigns a JavaScript object literal to the prototype, the Revealing Prototype Pattern assigns a function which is immediately invoked as with the Revealing Module Pattern:

Calculator.prototype = function () { }();


The complete prototype definition for Calculator is defined using the following syntax (this code assumes that a single calculator will be created). Looking through the code you’ll notice that it’s quite similar to the Revealing Module Pattern but assigns the container function to the Calculator’s prototype rather than to a variable.

 

var Calculator = function (cn, eq) {
    this.currNumberCtl = cn;
    this.eqCtl = eq;
};

Calculator.prototype = function () {
    var operator = null,
        operatorSet = false,
        equalsPressed = false,
        lastNumber = null,

        add = function (x, y) {
            return x + y;
        },

        subtract = function (x, y) {
            return x - y;
        },

        multiply = function (x, y) {
            return x * y;
        },

        divide = function (x, y) {
            if (y == 0) {
                alert("Can't divide by 0");
            }
            return x / y;
        },

        setVal = function (val, thisObj) {
            thisObj.currNumberCtl.innerHTML = val;
        },

        setEquation = function (val, thisObj) {
            thisObj.eqCtl.innerHTML = val;
        },

        clearNumbers = function () {
            lastNumber = null;
            equalsPressed = operatorSet = false;
            setVal('0',this);
            setEquation('',this);
        },

        setOperator = function (newOperator) {
            if (newOperator == '=') {
                equalsPressed = true;
                calculate(this);
                setEquation('',this);
                return;
            }

            //Handle case where = was pressed
            //followed by an operator (+, -, *, /)
            if (!equalsPressed) calculate(this);
            equalsPressed = false;
            operator = newOperator;
            operatorSet = true;
            lastNumber = parseFloat(this.currNumberCtl.innerHTML);
            var eqText = (this.eqCtl.innerHTML == '') ?
                lastNumber + ' ' + operator + ' ' :
                this.eqCtl.innerHTML + ' ' + operator + ' ';
            setEquation(eqText,this);
        },

        numberClick = function (e) {
            var button = (e.target) ? e.target : e.srcElement;
            if (operatorSet == true || 
                this.currNumberCtl.innerHTML == '0') {
                setVal('', this);
                operatorSet = false;
            }
            setVal(this.currNumberCtl.innerHTML + button.innerHTML, this);
            setEquation(this.eqCtl.innerHTML + button.innerHTML, this);
        },

        calculate = function (thisObj) {
            if (!operator || lastNumber == null) return;
            var displayedNumber = parseFloat(thisObj.currNumberCtl.innerHTML),
                newVal = 0;
            //eval() would've made this a whole lot simpler
            //but didn't want to use it in favor of a more
            //"robust" set of methods to demo patterns
            switch (operator) {
                case '+':
                    newVal = add(lastNumber, displayedNumber);
                    break;
                case '-':
                    newVal = subtract(lastNumber, displayedNumber);
                    break;
                case '*':
                    newVal = multiply(lastNumber, displayedNumber);
                    break;
                case '/':
                    newVal = divide(lastNumber, displayedNumber);
                    break;
            }
            setVal(newVal, thisObj);
            lastNumber = newVal;
        };

    return {
        numberClick: numberClick,
        setOperator: setOperator,
        clearNumbers: clearNumbers
    };
} ();


Looking through the code you’ll see that instead of assigning a JavaScript object literal to the prototype (as with the Prototype Pattern) a function is assigned instead. This makes the code a lot cleaner compared to the Prototype Pattern - in my opinion anyway. It also allows you take advantage of public/private visibility functionality through the return block so that only functions accessible to external objects are exposed.

There’s something interesting that happens with variables though especially if you plan on creating more than one Calculator object in a page. Looking at the public functions you’ll see that the “this” keyword is used to access the currNumberCtl and eqCtl variables defined in the constructor. This works great since the caller of the public functions will be the Calculator object instance which of course has the two variables defined. However, when one of the public functions calls a private function such as setVal(), the context of “this” changes and you’ll no longer have access to the two variables. There are a few tricks that can be used to deal with this, but to work around the context change I simply pass “this” from the public functions into the private functions. Although that technique works, it could certainly get messy if you have private functions calling a lot of other private functions. It’s definitely something to be aware of (if you happen to have a nice trick for handling that please leave a comment).

An instance of the Calculator can be invoked using the following code: 

var calc;
window.onload = function () {
    var cn = document.getElementById('currNumber');
    var eq = document.getElementById('eq');
    calc = new Calculator(cn, eq);
};


It's important to note that this code assumes that a single Calculator object will be created. If multiple objects were created we'd have a problem since several variables such as operator, operatorSet, etc. are defined in the prototype function and would be shared across all instances. As you type in one calculator you'd see the values reflected in the other calculators which wouldn't be right. Check out the code download below for an example that moves all of the variables into the constructor in situations where multiple instances need to be created.

Also note that the "calc" variable above is a global variable which isn't ever recommended in a "real" app. Although in this case we can get away with it (it's just a simple demo), in a real app you'd likely want to prefix it with a namespace. Something like the following:

var myNS = myNS || {};
...
myNS.calc = new Calculator(cn, eq);


As with any discussion of patterns, this blog series only scratches the surface of what can be done. However, I hope it provides a good starting point for converting your JavaScript code from “function spaghetti code” into a more structured type of code.

Demos of all the patterns covered in this series can be downloaded below.

Download Code



Pluralsight Course - Structuring JavaScript Code in HTML5 Applications

If you're interested in additional information about structuring JavaScript code check out my Pluralsight course. Here's a sample from the course covering closures.

Demo - Working with Closures in JavaScript


comments powered by Disqus

8 Comments

  • I like this interesting post! It's cool!

  • Hey Dan, nice series. I noticed one potential issue pertaining to your example of the Revealing Prototype Pattern. Setting the prototype to an object that is returned by a function will create a closure at the prototype level. Given that there will only be one instance of the prototype for all instances of Calculator, it appears that the local function 'closure' variables (like currNumberCtl and eqCtl) will be shared! This is probably not the desired result. - Shouldn't the instance variables be declared at the instance level (i.e. within the Constructor)? - And then accessed from within the prototype as this.varName? I haven't run your code but I believe that it will not work for multiple instances.

  • Graham: Thanks for adding a comment. You're 100% correct - a closure would be created on the two variables passed in so they could be changed by another instance and things would get messed up in that situation. I debated leaving the code "as is" since I never intended for more than 1 calculator on a page, however, in real-life there are certainly many cases where multiple object instances may need to be created so I thought I'd update things to handle that. The new code you see above handles multiple instances. However, it's a bit tricky with the context of "this" changing. I added a simple way to handle that and a small discussion about it but if you have other suggestions I'd be interesting in hearing them.

    Thanks,
    Dan

  • Dan: I prefer using the javascript 'call' function when accessing the private functions. Then both public and private functions can use the 'this' function (i.e. there is no need for a extra thisObj parameter). Here's a trivial example: http://jsfiddle.net/bonneville/fLwtd/

    Cheers
    Graham

  • Don't know for sure, but instead of passing the context as a named parameter, you could also use "call" to pass the context along with the function call right?

    "setVal = function (val) {
    this.currNumberCtl.innerHTML = val;
    },

    setEquation = function (val) {
    this.eqCtl.innerHTML = val;
    },

    clearNumbers = function () {
    lastNumber = null;
    equalsPressed = operatorSet = false;
    setVal.call(this, '0');
    setEquation.call(this, '');
    },
    "

    Regards,
    Wes

  • Wes: Thanks for the comment. Completely agree and have been wanting to upgrade that since it's a cleaner solution I think. Not enough time in the day...I'll get to it eventually. :-) Thanks again.

    Dan

  • if you are looking to easy extend your object, since o.prototype={} overrides the prototype simply do an extend base method such as

    function extend(o,p){
    for(prop in p){
    o.prototype[prop]=p[prop];
    };
    return o;
    }

    Then:

    extend(calculator, {
    numberClick: numberClick,
    setOperator: setOperator,
    clearNumbers: clearNumbers
    })

    Cheers
    Keith Chadwick

  • This is a nice pattern generally - I'm already using this to implement inheritance by extending prototypes. Code such as

    var DatedRating = function (description, date) {
    this.description = description;
    this.date = date;
    };

    DatedRating.prototype = $.extend(
    DatedState.prototype,
    RatingDisplayer.prototype);

    There's two pieces of the puzzle missing for me to give me the things I miss from class based inheritance. There's no way to implement "protected" members that I can see - create properties in a base prototype that inheriting prototypes can utilise, but the outside world can't.

    And the other piece is accessing private members from within a constructor. I'd like to be able to do this because I often want my objects to be immutable. The Revealing Module Pattern doesn't suffer from this limitation as the init function has access to "private" members. As I'm almost always wanting to limit access to the values I set from the constructor, this is an annoyance.

    So we're in the situation, as far as I can see, where we have the Revealing Prototype Pattern with the constructor limitation I mention, or Revealing Module Pattern, which has no inheritance story I can see. I must admit, I miss classes - I want inheritance, and I want information hiding.

Comments have been disabled for this content.