Techniques, Strategies and Patterns for Structuring JavaScript Code

JavaScript has come a long way since the mid-90s when I first started working with it in Netscape 3 and Internet Explorer 3. Back in the day I thought JavaScript was a painful to use but over the years I’ve learned to love it and appreciate what it offers as a language.  JavaScript is quite flexible and can perform a wide variety of tasks on both the client-side and server-side. In fact, I used to prefer it to VBScript on the server-side when writing classic ASP applications and today we have server-side frameworks such as Node.js that are JavaScript based. With the rise of HTML5 and new features such as the Canvas API and SVG JavaScript is more important than ever when building applications. As applications use more JavaScript it’s important that the code is structured in a way that’s easy work with and maintain.

Although JavaScript isn’t designed with the concept of classes or object oriented programming in mind as with C# or Java, with a little work you can achieve similar results. In this series of posts I’ll discuss a few popular techniques/strategies/patterns (pick whichever term you prefer) for structuring JavaScript to encapsulate functionality much like classes do, hide private members, and provide a better overall re-use strategy and maintenance story in applications.

I’ll use a calculator example throughout the posts to demonstrate different techniques that can be used for structuring JavaScript code. I decided on a calculator since it provides a simple starting point that everyone understands without needing a detailed explanation. An example of the calculator interface is shown next.

image

I use specific add, subtract, multiply, divide functions in the code that’ll be shown mainly because I tend to avoid eval() and I wanted to add enough functions to realistically demonstrate why taking the time to learn JavaScript code structuring techniques and patterns is worthwhile. In this first post in the series we’ll look at the technique most people use when writing JavaScript code, examine the role of closures, and discuss different ways to define variables. After that I’ll add additional posts covering the patterns mentioned earlier.

 

Function Spaghetti Code

Most people (including myself) start out writing JavaScript code by adding function after function into a .js or HTML file. While there’s certainly nothing wrong with that approach since it gets the job done, it can quickly get out of control when working with a lot of code. When lumping functions into a file, finding code can be difficult, refactoring code is a huge chore (unless you have a nice tool like Resharper 6.0), variable scope can become an issue, and performing maintenance on the code can be a nightmare especially if you didn’t originally write it. The following code sample demonstrates using the function based approach to create a simple calculator that I threw together. It’s not perfect, but it gets the job done for the pattern samples that will be posted later.

 

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;
}


Although I’m quite confident this code can be refactored in some manner within the functions (it was thrown together quickly for demonstration purposes), you can see it performs a few key calculator features such as handling arithmetic operations, detecting when operators are selected and performing calculations. Although everything shown in the code is standard JavaScript and works fine, as the number of functions grows things can quickly get out of hand. You can put the code in a file named calculator.js and then use it in as many pages as you’d like. However, if you come from an object oriented language you’d probably like to encapsulate the functionality into the equivalent of a “class”. Although classes aren’t supported directly in JavaScript, you can emulate the functionality using different types of patterns.

Another problem with this type of code is that any variables defined outside of functions are placed in the global scope by default. The script shown above adds 6 variables to the global scope (the functions get added as well by the way). This means that they can more easily be stepped on or changed by anything in your script or another script that may be using the same variable names. It’d be nice to localize the global variables and limit their scope to avoid variable and scope conflicts. Fortunately that can be done using functions. However, if you define a variable in a function it goes away after the function returns right? That problem can be remedied by using closures which are an important part of the JavaScript patterns that I’ll cover in this series.

 

What are Closures?

The patterns that will be discussed in this series rely on a key concept in JavaScript called closures.  If you’re new to closures then I highly recommend reading the JavaScript Closures for Dummies article since it provides a nice overview along with several samples.  Closures are important because they allow stateful objects to be created without relying on variables defined in the global scope. By using closures you can emulate features found in the class approach taken by object-oriented languages such as C# and Java.

A closure is created when a function has variables that are bound to it in such a way that even after the function has returned, the variables stick around in memory. So what’s the magic that allows variables to be “bound” in such a way that they stick around even after a function returns? The answer is nested functions. When one function has a nested function inside of it, the nested function has access to the vars and parameters of the outer function and a “closure” is created behind the scenes. Douglas Crockford explains this with the following quote:

“What this means is that an inner function always has access to the vars and parameters of its outer function, even after the outer function has returned.”

To better understand closures examine the following code representing a standard JavaScript function without any closures:

function myNonClosure() {
    //variable will not be stored in a closure between calls
    //to the myNonClosure function
    var date = new Date();
    return date.getMilliseconds();
}


When the myNonClosure function is invoked the date variable will be assigned a new Date object. The function then returns the milliseconds. Calling the function multiple times will cause the date variable to be assigned a new value each time. This is of course the expected behavior. With a closure, a variable can be kept around even after a function returns a value. An example of a function named myClosure() that creates a closure is shown next:

//closure example 
function myClosure() {
    //date variable will be stored in a closure
    //due to the nested function referencing it
    var date = new Date();

    //nested function 
return function () { var otherDate = new Date(); return "Closure variable value for milliseconds: <span class='blue'>" + date.getMilliseconds() + "</span><br>Non closure variable value for milliseconds: <span class='red'>" + otherDate.getMilliseconds() + "</span>"; }; }


Looking through the code you can see that a variable named date is assigned a Date object which is similar to the variable shown earlier. However, notice that myClosure returns a nested function which references the date variable. This creates a closure causing the date variable to be kept around even after a value has been returned from the function.  To see this in action the following code can be run:

window.onload = function () {
    //Using a closure
    var output = document.getElementById('Output'),
        closure = myClosure();
    output.innerHTML = closure();
    setTimeout(function() {
        output.innerHTML += '<br><br>' + closure();
    }, 1500);
};


The code first references the myClosure() function and stores it in a variable named “closure”. The nested function is then called with the closure() call (note that the name “closure” could be anything – I chose it simply to make its purpose obvious) which invokes the function and returns the current milliseconds. Next, a timeout is set to execute closure() again after 1.5 seconds have elapsed. The results of running the code are shown next.  They demonstrate how the date variable is kept around even across multiple calls to the myClosure function. This is an important feature of JavaScript that is leveraged by the different patterns that will be shown.


image

Here’s a final example of a closure for you to study. It follows one of the patterns that will be shown later in this series. Note that the myNestedFunc variable references a nested function that accesses the date variable.

var myClosure2 = function () {
    var date = new Date(),
        myNestedFunc = function () {
            return "Closure for myNestedFunc: " + date.getMilliseconds();
        };
    return {
        myNestedFunc: myNestedFunc
    };
} ();

This code is called using the following syntax. 


output.innerHTML += '<br><br>'+ myClosure2.myNestedFunc();


Defining Variables

Defining variables in JavaScript is one of the more simple aspects of the language. However, there are a few different ways to do it. For example, the following code is completely valid and what most people getting started with JavaScript do:

 

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


Although this code works fine, tools such as JSLint for Visual Studio will let you know to define the variables differently. In the posts that follow you’ll see code similar to the following when defining variables.  It only uses the JavaScript var keyword once and then separates variables with a comma. The code ultimately does the same thing as the code above but it reduces the size of the script and is more readable once you get used to it. Here’s an example of defining variables that keeps JSLint and other tools happier when they inspect your code:

 

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


In the next post I’ll discuss the Prototype Pattern and how you can use it to convert function spaghetti code into a more structured object.

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

9 Comments

  • Hi Dan -- As usual, another well-written article on a highly relevant topic with examples that are easy to follow. Can't wait for the follow-ups on Patterns. Thanks!

  • This is a great discussion.

    I get very scared when thinking about trying to do big projects in javascript and look at the typical mess.

    Thanks!!

  • This series is a wonderful idea; I hope you give it enough attention. However I cannot agree with you in this first part. All languages, including C# and Java, had this way of defining variables and not once I've heard of (or felt like) it being a good idea. ReSharper, for example, takes that syntax and splits it up again into separate, atomic variable definition statements. I don't think it's more readable, either.

  • Siderite: I felt the same way initially and have never liked doing that in C#. But, since JavaScript code needs to be kept as small as possible every little var counts. :-) I like the approach now - but it took awhile to grow on me. Either way works so it's definitely something each dev can ignore if they want. Once some of the patterns are used I personally think it makes a big difference not only in character count, but also in readability.

  • Shouldn't the calling code for myClosure2 be:

    output.innerHTML += '

    '+ myClosure2().myNestedFunc();

    You need to call myClosure2 to return the object, otherwise it returns the myClosure2 function

  • Zev: Thanks for reading the post. Normally that would be correct since simply calling a function like that will return the function as you point out. However, in this case the function is self-invoking so it's already called. Check out the () at the end of the myClosure2 definition.

  • [quote]The script shown above adds 6 variables to the global scope[/quote]
    Don't forget, your functions get added to the global scope as well, so it's more than just 6 variables that get added to the global scope.

  • Peter: Excellent point - functions definitely go in the global scope as well by default. Yet another reason to use some of the patterns I'll be covering. :-)

  • This is really great. Thanks!

Comments have been disabled for this content.