Long switch case statements, and heavily indented if/else statements can indicate a code smell. I've seen switch cases implemented with no defaults, when a simple object lookup would have done a better job.
An object lookup is more readable, and versatile. It can be dynamic, it can call a function to return the data from whichever input you give it.
One anti-pattern I see often is switch cases with no default case, more in JavaScript than any other language. The issue with having no default case is that it can and will, and often does – fall through silently.
Switch cases are really good for when you have many different scenarios which apply to many different inputs. However when dealing with say, data returned from an API, an object lookup can serve you better than a switch case, and is more readable than a verbose if/else.
Let's look at a real life example, say we want to get the users' username from their email.
An if statement might look like this on its own. Fine for this example, but if we wanted to do this for a large dataset or for values which were dynamic - it would become unwieldy and we can't do dynamic with static values. We would need to iterate over the data or input.
function getUsername(name) {
const email = '';
if (name === 'user1') {
email = 'user1@mail.com';
} else if (name === 'user345') {
email = 'user345@mail.com';
} else if (name === 'user20') {
email = 'user20@mail.com';
} else {
// default case
email = 'User not found!';
}
return email;
}
A good example of a switch case would be if a user had multiple emails connected to one username, so we could do a lookup with a switch, based on that. But again, we're tied to being static having to know beforehand what value returns what.
function getUsername(email) {
let username = '';
switch (email) {
case 'user1@mail.com':
case 'user1@othermail.com':
username = 'user1';
break;
case 'user345@mail.com':
case 'user345@othermail.com':
username = 'user345';
break;
case 'user20@mail.com':
case 'user20@othermail.com':
username = 'user20';
break;
// Note: Switch cases should always have a default statement
// otherwise they may fail silently and cause problems.
// Perhaps don't use this, use if/else.
// Or explicitly throw an error in the default case.
default:
username = 'Not found!';
}
return username;
}
But what if we have an object or array of user data which we want to conditionally lookup and retrieve values from? Or what if we have a lot of different entries, a switch/case or if/else are going to be unreadable, unwieldy and potentially restrictive.
Object lookups to the rescue!
function getEmailFromUsername(name) {
return {
user1: 'user1@mail.com',
user345: 'user345@mail.com',
user20: 'user20@mail.com'
}[name];
}
getEmailFromUsername('user1'); // 'user1@mail.com'
We can do something like this, which is very readable and can take a lot of key/value pairs. Looks neat and tidy.
If you're wondering what's going on here, we're using bracket notation to get the value out of the object. What you might have done before is get the value from a key reference to an object by way of it being stored in a variable using either dot notation or bracket notation.
var myObj = {
user1: 'user1@mail.com',
user345: 'user345@mail.com',
user20: 'user20@mail.com'
};
myObj.user1; // 'user1@mail.com'
myObj['user1']; // 'user1@mail.com'
So what we're doing, is cutting out the middleman and accessing the value from the key right on the object itself.
Finally, if we wanted to dynamically lookup an email from some data object, which we've fetched from an API or database or some manifest.json -- it would look something like this.
const myData = {
user1: 'user1@mail.com',
user345: 'user345@mail.com',
user20: 'user20@mail.com'
};
function getEmailFromUsername(data, name) {
return data.hasOwnProperty(name) ? data[name] : 'Not found!';
}
getEmailFromUsername(myData, 'user1'); // 'user1@gmail.com'
getEmailFromUsername(myData, 'bob'); // Not Found!
Obviously if/else and switch/case conditionals are still tools with their correct uses. But if you:
- have many different values and types to check
- want to make a function with parameters to allow for arguments to be entered dynamically from different sources
- or just want your code to be more readable and flexible