You could do this..

//Example 1 function getEventTarget(evt) { if (!evt) { evt = window.event; } if (!evt) { return; } var target; if (evt.target) { target = evt.target; } else { target = evt.srcElement; } return target; }

or you could do this…

//Example 2 function getEventTarget(evt) { evt = evt || window.event; return evt && (evt.target || evt.srcElement); }



To avoid ambiguity I’ll explain how I’m using a couple of terms in this article:

• statement branching: any construct that alters the sequence of statement execution within the global or functional scope. These include if, else, switch, for and while statements.

• micro-branching: conditional logic contained within a statement that has no effect on the statement execution seqeunce. The following operators facilitate micro-branching: ternary, && and ||.

OK back to the examples…

Example 1 employs statement branching, i.e. its statements are designed to execute non-linearly. Aside from the obvious bloating effect, statement branching tends to become unintuitive as it progresses (its really just one step up on the food chain from the widely discredited goto statement). As humans we are inclined to read function code top-down, line by line through to the last line. Logic built on statement branching forces us to mentally track each possible execution sequence. As branching logic gets more complex the number of forking paths increases and it becomes easy to overlook edge-case flow scenarios. Bugs love overlooked scenarios.

Example 2 uses micro-branching. The logic flows sequentially from top to bottom and even from left to right. There are no forks in the road. There is only one return statement and its at the bottom where we expect it. Best of all it’s short. Nothing is wasted. In fact it’s terse enough to be barely procedural at all.

Statement branching is necessary and useful but having the full toolkit of alternatives at hand helps to keep our JavaScript readable, concise and robust. There’s also an ideological element here: there’s a lot of power in JavaScript’s functional capabilities, but we need to let go of some procedural baggage in order to unleash it.

Alternatives to statement branching fall into two broad categories: micro-branching and no branching at all. Let’s dig deeper into each:

Micro-branching strategies

Guards (&&) and Defaults(||)

The logical boolean operators && and || are familiar syntax in many languages.

JavaScript has a liberal approach to these operators:

• Constructs formed by logical boolean operators can be used as expressions within statements or can form the entire statement

• The operands need not evaluate to booleans but will be coerced to booleans to facilitate the logical operation

• The result of evaluating a logical boolean expression need not be a boolean value

(see ECMA 5 11.11)

This provides for some gorgeously succinct non-branching conditional logic:

//invoke callback if there is one callback && callback(); //delay by argument or 20 delayBy(delay || 20); //remove node from its parent node && node.parent && node.parent.removeChild(node); //log a test in the console id we have one window.console && console.log('test');

The Ternary operator

Also (and more clumsily) known as the conditional ?: operator, this is another cross-language standard which we can leverage to lay down conditions without affecting the sequence of statement execution.

When used badly ternary operators are no better than bad imitations of if/else branching. The perplexed smiley in the middle of this one says it all:

//Bad example - ternary that thinks its an if/else. var a = 2, b = 1; a ? ( b++, a = a*2, console.log(a,b) ):( b--, a = a/2, alert(a + " " + b) );

However when used as a conditional assignment or intra-statement switch, the logic is clean and easy to follow.

//make an array of the args if any, or return empty array var args = arguments ? toArray(arguments) : []; //end game or go to next level gameOver ? finally() : nextLevel();

Function Delegation

As if/else blocks get bigger and/or nested they get harder to follow. If the statement block(s) are more than a few lines it generally suggests the need for an additional function or functions.

Here is a function for dropping a dragged item in a box. Firstly using if/else and multiple bailing returns….

function itemDropped(item, location) { if (!item) { return false; } else if (outOfBounds(location) { var error = outOfBounds; server.notify(item, error); items.resetAll(); return false; } else { animateCanvas(); server.notify(item, location); return true; } }

…and secondly reimplemented to use function delegation, a ternary and one trailing return per function. Note the added bonus of being able to name your conditions – like a built-in comment.

function itemDropped(item, location) { var dropOut = function() { server.notify(item, outOfBounds); items.resetAll(); return false; } var dropIn = function() { server.notify(item, location); animateCanvas(); return true; } return !!item && (outOfBounds(location) ? dropOut() : dropIn()); }

Be careful with “bailing” returns

Some things just have a natural place. Birds in the sky, fish in the sea and a return statement at the end of a function. Short circuiting a function when an variable is null or some other non-useful value might be handy for developers but it can sometimes be a source of obfuscation for reviewers and bug fixers (and more often than not the bug fixer is the original developer). I’m as guilty as anyone else when it comes to bailing returns but other people’s code is often more readable without them. The example just above and Example 2 at the beginning of this article illustrate strategies for avoiding bailing returns.

Non-branching strategies

Property look-ups (a.k.a. dispatch tables)

My very first blog post touted my preference for hash look-ups over switch statments so I won’t re-hash(!) all the same arguments here. Suffice to say, functions are most expressive when they eschew data considerations and focus on form. Defining data dependent action properties elsewhere enables just such a separation.

Here’s an example that reacts to a toolbar button being clicked in a file manager type application. First using a switch. Note the clicked function is specific to fileManager and as a consequence we start to build up some ominous looking namespace chaining:

fileManager.toolbar.clicked = function(buttonId) { switch(buttonId) { case 'open': fileManager.openNew(true); break; case 'save': fileManager.saveSelected(true); break; case 'run': fileManager.executeSelected(true); break; default: coreUtils.notImplemented(); } } fileManager.toolbar.clicked('save');

Now here’s an alternate implementation using a hash table for lookup. Adding a new button will be a breeze – just add a new property to the actions object. And the clicked function is now generic – action objects can be passed as parameters from any toolbar.

fileManager.toolbarActions = { 'open': {fn: fileManager.openNew, args: [true]}, 'save': {fn: fileManager.saveSelected, args: [false]}, 'run': {fn: fileManager.execSelected, args: [false]}, 'default': {fn: coreUtils.notImplemented, ctxt: coreUtils}, } toolbar.clicked = function(actions, buttonId) { var action = actions[buttonId] || actions['default']; action.fn.apply(action.ctxt, action.args); } toolbar.clicked(fileManager.toolbarActions, 'save');

Higher Order Functions

One of the de facto characteristics of Functional Programming is the use of higher order functions (functions into which other functions are injected as data) to encapsulate procedural logic. It’s very hard to write purely functional JavaScript – there will almost always be a reliance on state and in-function side effects – and at its heart the language is built on imperative logic; however it is possible to de-emphasize the imperative nature of the language (branching, loops, disruptors) and shift the emphasis toward functional building blocks. Again humans are much better at validating concepts than validating non-linear path logic.

Array functions

All the major JavaScript frameworks define a rich set of higher order functions for use with Arrays. ECMA 5 also defines a similar set of functions and they are already implemented in all browsers except for IE<=8.

(A note on performance – if your array is very large you might see some performance degradation with the higher order array function – every function call carries a small but cumulative cost. As with all coding – write it for sturdiness and readability, optimize later if you have to – and you probably won’t have to)

Consider a function that returns all words longer than four letters. First the naive approach. The array is short and the test is simple but the logic will still touch about 50 statements in a loopy-doopy sequence.The author is forced to churn out the same mundane looping syntax that she will probably repeat multiple times elsewhere. It’s donkey work that increases the probability of errors and only serves to obfuscate the more meaningful content.

function dropShortWords(words) { var wordArray = words.split(" "); var longWords = []; for (var i=0; i<wordArray.length; i++) { var word = wordArray[i]; if (word.length>4) { longWords.push(word); } } return longWords.join(" "); } dropShortWords("The quick brown fox jumped over the lazy dog"); //"quick brown jumped"

… and here is we define the same function using the higher order filter function. Four lines and we left the looping and branching to the safety of an industry tested utility. Moreover with the distraction of the looping syntax removed, the intent of the function becomes clearer.

//(will not work in IE<9) function dropShortWords(words) { var longWords = words.split(" ").filter(function(word){ return word.length>4; }); return longWords.join(" "); } dropShortWords("The quick brown fox jumped over the lazy dog"); //"quick brown jumped"

Functions as Data

Functions are first class objects in JavaScript and this allows us to pass them as parameters to other functions. Amongst other things, this provides an alternative to branching.

Here is a simple calculator. With ifs….

var calc = { run: function(op, n1, n2) { var result; if (op == "add") { result = n1 + n2; } else if (op == "sub" ) { result = n1 - n2; } else if (op == "mult" ) { result = n1 * n2; } else if (op == "div" ) { result = n1 / n2; } return result; } } calc.run("sub", 5, 3); //2

…and now using run as a higher order function instead:

var calc = { add : function(a,b) { return a + b; }, sub : function(a,b) { return a - b; }, mult : function(a,b) { return a * b; }, div : function(a,b) { return a / b; }, run: function(fn, a, b) { return fn && fn(a,b); } } calc.run(calc.mult, 7, 4); //28

Polymorphism

This strategy is well known to anyone versed in classical OOP. At its best it’s smart and intuitive. No longer does one method have to implement complex branching based on type – instead each type knows how to implement the method in it’s own way. However I must confess, these days its easy to get hierarchy fatigue. Even with the best IDEs, complex hierarchies have a tendency to be just as off-putting as a long and nested if else construct. No one can keep a mental model of a sophisticated class or object tree and latterly inserting a new member or method into that tree can be very painful. Adding objects to spaghetti code just gets you spaghetti with meatballs. Moreover, even though prototypical inheritance is a viable alternative to classical inheritance, in JavaScript I find I rarely have a genuine need for inheritance at all.

In the linked article I include an example of polymorphic messaging across types as an alternative to statement branching.

Putting it all together

I’m by no means the last authority on coding style and this article is as much about investigation as it is about recommendation. You should use your judgment to write code that is as tidy and as understandable as you can make it (subject to common-sense performance considerations). I hope this article helps a little bit towards that goal.

Comments and Questions are very welcome