Javascript Conditionals

As we all know, Javascript is a very flexible language. In the article I will show different ways to execute conditional code by using some common idioms from Javascript and general object-oriented techniques.

Default values

Javascript does not support default values for arguments and it is common to use an if statement or a conditional expression to set default values.

function swim(direction, speed, technique) {
	// Default value with if statement
	if (!direction) direction = 'downstream';

	// Default value with conditional operator
	var speedInMph = speed ? speed : 2;
}

I usually prefer to use an or-expression instead. The short-circuiting or, ||, avoids the repetition of the conditional operator and is, in my opinion, more readable. Another advantage of avoiding repetition is that a slow executing function condition such as fastestSwimmer() will avoid the performance penalty of calling the function twice.

// Default value with or.
var swimTechnique = technique || 'crawl';

// Function is only invoked once
var siwmmer = fastestSwimmer() || 'Michael Phelps';
}

Naturally, this technique is not limited to default arguments, it can be used to set default values from object literals too.

options = { kind: 'Mountain Tapir', }
var kind = options['kind'] || 'Baird Tapir';

A simple, yet useful, technique.

Call callback if present

Another idiom in Javascript, especially in Node, is passing callbacks to other functions. But, sometimes the callbacks past in are optional. In this case we can use short-circuiting and, &&, instead.

function updateStatistics(data, callback) {
	var result = doSomethingWithData(data);
	// Call the callback if it is defined
	if (callback) return callback(result);
}

function (data, callback) {
	var result = doSomethingWithData(data);
	// The last evaluated value of the `&&` is returned
	return callback && callback(result);
}

I, personally, prefer the first form with the explicit if because I think it communicates my intent better but, it is good to know about the technique anyway.

Lookup Tables

If you have code that behaves differently based on the value of a property, it can often result in conditional statements with multiple else ifs or a switch cases.

if (kind === 'baird')
	bairdBehavior();
else if (kind === 'malayan')
	malayanBehavior();
else if (kind === 'mountain')
	mountainBehavior();
else if (kind === 'lowland')
	lowlandBehavior();
else
	throw new Error('Invalid kind ' + kind);

I find this kind of code ugly and I don't think it looks any better with a switch statement. I prefer to use a lookup table if there is more than two options.

var kinds = {
	baird: bairdBehavior,
	malayan: malayanBehavior,
	mountain: mountainBehavior,
	lowland: lowlandBehavior
};

var func = kinds[kind];
if (!func)
	throw new Error('Invalid kind ' + kind);
func();

I find this code a lot clearer since makes it clear that the else clause handles an exceptional case and that the normal cases works similarly.

Missing Objects

If similar conditionals appear in multiple places in my code, it is a sign that I am missing an object somewhere. Since Javascript is duck typed I can use the same technique as above to create objects instead of just functions.

var kinds = {
	baird: { act: bairdBehavior, info: bairdInfo },
	malayan: { act: malayanBehavior, info: malayanInfo },
	mountain: { act: mountainBehavior, info: mountainInfo },
	lowland: { act: lowlandBehavior, info: lowlandInfo },
};

var tapir = kinds[kind];
if (!tapir)
	throw new Error('Invalid kind of tapir ' + kind);

I prefer to have this kind of code on the borders of my application. That way the code inside my core domain doesn't have to deal with complicated conditional logic. Polymorphism for the win!

Null Objects

If I notice that in many places I have to check fornulls, it is usually a sign that I haven't handled the special null case properly. In the example above I have handled it properly since I throw an Error if the kind of tapir does not exist. But sometimes it is not an error when the value is missing.

// If a non existant kind is used, tapir will become null
var tapir = kinds[kind];

// In other places of the code
if (tapir)
	tapir.act();

// Somewhere else
if (tapir)
	return tapir.info();

This type of code is rather unpleasant and it is time to break out the Null Object.

var tapir = kinds[kind];
// If a non existant kind is used I use a Null Object
if (!tapir)
	tapir = { act: doNothing, info: unknownTapirInfo }

// In other places of the code the conditionals are gone.
tapir.act();

// Somewhere else, no special case here.
return tapir.info();

Null Objects are not appropriate everywhere but, I often find it very enlightening to have them in mind when I write code.

Summary

There are a lot of elegant ways to deal with conditional code in Javascript. I didn't even mention inheritance since it works similarly to the object approach I showed above. But if I need multiple instances of something I would of course use polymorphism through inheritance instead.

This Post Has 3 Comments

  1. Claudio

    Hi there! Been following jayway for a short while now (on the soon-to-be-defunct google reader, btw). Lots of interesting content, but this one post especially have put a smile in my face, and made me want to write a short “kudos”. Many interesting tips on this little fascinating language. Thanks for taking the time to share it :)

  2. Anders Janmyr

    @Claudio, I’m glad you liked it, it was my pleasure to share it.

  3. rikard qvarforth

    Nice post really liked the Null object example :)

Leave a Reply