JavaScript, like most languages of the C-genus, has a switch statement which is a really handy alternative to the standard if conditional. switch is a bit of an underdog in the world of conditionals, usually only coming out when there would normally be many else statements.
Interesting Features
Fallthrough
switch has a really interesting behavior called fallthrough which is just as dangerous as it is powerful. Consider the following code which:
function dateSuffix(date) {
switch (date) {
case (1):
case (21):
case (31):
dt = "st";
break;
case (2):
case (22):
dt = "nd";
break;
case (3):
case (23):
dt = "rd";
break;
default:
dt = "th";
}
return date + suffix;
}
While fallthrough is really useful, the problem with fallthrough is that it’s implicit. There is no clue to the developer that fallthrough has actually occurred other than his data being modified, or worse, his program stops working.
Flexibility Through Expressions
One of the most powerful features of JavaScript’s switch implementation is that the entire control structure is based on expressions: The switched conditional can be an expression and the case values may also be expressions. Unlike the standard if statement, the conditional blocs (the case statements) are not enclosed in curly braces. Instead they too are expressions. This makes conditional breaks possible.
...
case (someValue):
if (isProperFormat(someValue)) break;
someValue = formatValue(someValue);
// intentional fallthrough
...
It should also be noted that because case blocks lack the use of curly braces, accidental fallthrough is quite easy. Simply forgetting the break statement will cause fallthrough and the next case will be evaluated.
Alternatives
The Simple Conditional
Conditionals are my personal favorite as they are explicit in their meaning. Code which is easier to read usually makes for less bugs down the road.
function dateSuffix(date) {
var suffix;
if (date === 1 || date === 21 || date === 31) {
suffix = 'st';
}
else if (date === 2 || date === 22) {
suffix = 'nd';
}
else if (date === 3 || date === 23) {
suffix = 'rd';
}
return date + suffix;
}
Lookup Tables
Lookup tables are a slightly more advanced version of switch statements. These are my personal favorite as they are generally much more flexible and can be crafted to be modified dynamically at runtime.
function dateSuffix(date) {
var suffixMap = {
'st' : (date === 1 || date === 21 || date === 31),
'nd' : (date === 2 || date === 22),
'rd' : (date === 3 || date === 23)
};
for (var suffix in suffixMap) {
if (suffixMap[suffix]) {
return date + suffix;
}
}
}
Best Practices
Despite some of the issues with switch, none of these are JavaScript-related. Rather these are simply issues with this control structure in general. It still remains that this is a very useful alternative to a standard conditional that, when used properly, can help improve the readability of your code.
Here are a few simple guidelines to keep in mind:
- case statements work best for short one-line operations. The more operations that follow a case statement, the easier it is to forget to add a break. If you find lots of nested operations inside of a case statement, you’re better off using one of the alternatives above.
- On the same note of preventing accidental fallthrough, make sure to always maintain proper indentation while working in case statements. I always add my break in before writing the actual code which gets executed.
- If fallthrough can’t be avoided, always document it inline with // intentional fallthrough or something similar. This will remind yourself (and other developers) that it is not a bug.
Nice write up. There’s a couple ways to accomplish the same logic depends on the situation. Sometimes you can do a simple array search ( with arr.indexOf or, in some cases, arr.toString().search ).
An example of this scenario comes up with my PHP code constantly:
$userInput = ‘#00ff00′;
$acceptableOptions = array(
‘red’ => ‘#ff0000′,
‘green’ => ‘#00ff00′,
‘blue’ => ‘#0000ff’,
);
if (in_array($userInput, $acceptableOptions)) {
// continue with user input …
}
else {
die(‘Invalid color option, dude.’);
}