Site Logo

Pixel-in-Gene

Exploring Frontend Development with Design / Graphics / Technology

Common Idioms in JavaScript development

These are some of the common idioms I find myself using again and again. I am going to keep this as a live document and will update as I discover more useful idioms.

Disclaimer: I’ll be using the Underscore library in all of my examples

Use Array.join to concatenate strings

It is quite common to build html in strings, especially when you are writing a custom formatter or just plain building simple views in code. Lets say you want to output the html for 3 buttons:

var html =
    '<div class="button-set">' +
    '<span class="button">OK</span>' +
    '<span class="button">Apply</span>' +
    '<span class="button">Cancel</span>' +
    '</div>';

This works, but consider the alternate version, where you build the strings as elements of an array and join them using Array.join().

var html = [
	'<div class="button-set">'
		'<span class="button">OK</span>',
		'<span class="button">Apply</span>',
		'<span class="button">Cancel</span>',
	'</div>'
].join('');

It reads a little better and can almost look like real-html with the identation ;)

Minimize use of if/else blocks by creating object hashes

Lets say you want perform a bunch of different actions based on the value of a certain parameter. For example, if you want to show different views based on the weather condition received via an AJAX request, you could do something like below:

function showView(type) {
    if (_.isObject(type)) {
        // read object structure and prepare view
    } else if (_.isString(type)) {
        // validate string and show the view
    }
}

function showWeatherView(condition) {
    if (condition === 'sunny') showView('sunny-01');
    else if (condition === 'partly sunny') showView('sunny-02');
    else if (condition === 'cloudy') showView('cloudy-01');
    else if (condition === 'rain') showView({ type: 'rain-01', style: 'dark' });
}

$.get('http://myapp.com/weather/today', function(response) {
    var condition = response.condition;

    // Show view based on this condition
    showWeatherView(condition);
});

You will notice in showWeatherView(), there is lot of imperative noise with if/else statements. This can be removed with an object hash:

function showWeatherView(condition) {
    var viewMap = {
        sunny: 'sunny-01',
        'partly sunny': 'sunny-02',
        cloudy: 'cloudy-01',
        rain: { type: 'rain-01', style: 'dark' },
    };

    showView(viewMap[condition]);
}

If you want to support more views, it should be easier to add it to the viewMap hash. The general idea is to look at a piece of code and think in terms of data + code. What part is pure data and what part is pure code. If you can make the separation, you can easily capture the data part as an object-hash and write simple code to loop/process the data. As a side note, if you want to eliminate the use of if/else, switch statements, you can have Haskell-style pattern-matching with the matches library.

Make the parameter value be of any-type

When you are building a simple utility library/module, it is good to expose an option that can be any of string, number, array or function type. This makes the option more versatile and allows for some logic to be executed each time the option value is needed. I first saw this pattern used in libraries like HighCharts and SlickGrid and found it very natural.

Let’s say you want to build a simple formatter. It can accept a string to be formatted using one of the pre-defined formats or use a custom formatter. It can also apply a chain of formatters, when passed as an array. You can have the API for the formatter as below:

function format(formatter, value) {
    var knownFormatters = {
            '###,#': function(value) {},
            'mm/dd/yyyy': function(value) {},
            'HH:MM:ss': function(value) {},
        },
        formattedValue = value;

    if (_.isString(formatter)) {
        // Lookup the formatter from list of known formatters
        formattedValue = knownFormatters[formatter](value);
    } else if (_.isFunction(formatter)) {
        formattedValue = formatter(value);
    } else if (_.isArray(formatter)) {
        // This could be a chain of formatters
        formattedValue = value;
        _.each(formatter, function(f) {
            formattedValue = format(f, formattedValue); // Note the recursive use format()
        });
    }

    return formattedValue;
}

As an addendum to a multi-type parameter, it is also common to normalize the parameter value to an object hash and remove type differences.

Use IIFE to compute on the fly

Sometimes you just need a little bit of code to set the value of an option. You can either do it by computing the value separately or do it inline by writing an Immediately Invoked Function Expression (IIFE):

var options = {
    title: (function() {
        var html = '<h1>' + titleText + '</h1>';
        var icons = '<div class="icon-set"><span class="icon-gear"></span></div>';

        return html + icons;
    })(),
    buttons: ['Apply', 'Cancel', 'OK'],
};

In the above code there is little bit of computation for the title text. For simple code like above it is sometimes best to have the logic right in there for improved readability.

Common Idioms in JavaScript development
Pavan Podila
Pavan Podila
October 7th, 2012