DEV Community

Cover image for Stop using if else
Rishav Jadon
Rishav Jadon

Posted on

Stop using if else

Recently, I had a take home assignment for a front end role, and I had to make a sort of Dashboard. I thought I did everything right, but I was rejected, partly on my carelessness, and also due to my code. I was using too many if/else statements everywhere! And I didn't know any better. But now I do, and I'm here to share that with you.

Most of us use if/else and switch statements whenever there is some conditional logic to handle. Although it might be a good idea to do that for one or two conditions here and there, using multiple if else statements chained together or big switch statements will make your code look very ugly, less readable and error prone.

function whoIsThis(character) {
    if (character.toLowerCase() === 'naruto') {
        return `Hokage`
    } else if (character.toLowerCase() === 'sasuke') {
        return `Konoha's Strongest Ninja`
    } else if (character.toLowerCase() === 'isshiki') {
        return `Otsutsuki being`
    } else if (character.toLowerCase() === 'boruto') {
        return `Naruto and Hinata's son`
    }
}
whoIsThis('')
Enter fullscreen mode Exit fullscreen mode

You see that we are repeating ourselves many times by writing multiple console.logs and if statements.

But there's an Object-Oriented way of doing this, and that is by using Objects.
Instead of writing if else blocks we just define an object which has the values we use in comparisons as keys, and the values we return as values of the objects, like so:

function whoIsThis(character) {
    const listOfCharacters = {
        'naruto': `Hokage`,
        'sasuke': `Konoha's Strongest Ninja`,
        'isshiki': `Otsutsuki being`,
        'boruto': `Naruto and Hinata's son`
    }

    return listOfCharacters[character] ?? `Please provide a valid character name`
}
Enter fullscreen mode Exit fullscreen mode

By using objects, we were able to make a sort of dictionary to look up to, and not use multiple if-else statements.

We can also make this better by using the Map object instead of using an object. Maps are different from normal objects:

  • They remember the original order of insertion
  • Unlike objects, we can use any type of data as key/value, not just strings, numbers and symbols.
function whoIsThis(character){
const mapOfCharacters = new Map([
['naruto', `Hokage`],
        ['sasuke', `Konoha's Strongest Ninja`],
        ['isshiki', `Otsutsuki being`],
        ['boruto', `Naruto and Hinata's son`]
])
return mapOfCharacters.get(character) ?? `Please provide a valid character name`
}
Enter fullscreen mode Exit fullscreen mode

Thanks for reading this short article, if you liked it, you can support my work at https://www.buymeacoffee.com/rishavjadon

Oldest comments (65)

Collapse
 
naveennamani profile image
naveennamani

This only works if you're comparing a single variable with known values. For other cases you've to use if/else

Collapse
 
rjitsu profile image
Rishav Jadon

Can you share any example where you cannot make use of this?

Collapse
 
naveennamani profile image
naveennamani
if(a===10) {
...
} else if(b===20) {
...
} else {
...
}
Enter fullscreen mode Exit fullscreen mode
Thread Thread
 
rjitsu profile image
Rishav Jadon

I meant a real example from code. Anyways, we need to write good code in order to not add conditionals like these.

Thread Thread
 
bubster profile image
TvO • Edited

This is a perfectly fine example of real code lol.

Thread Thread
 
coolprofessor profile image
coolprofessor • Edited

Here:

function signIn(user,password){
    if( user === 'bob'  && password === '' ){
         return true
    }else if( user === 'sally' && password === 'gitIsCool7#6' ){
         return true
    }else if( user === 'jerry' && password === 'hackme123' ){
         return true
    }
}

signIn('jerry','hackme123');
//will return ability to sign in (boolean)
Enter fullscreen mode Exit fullscreen mode

@naveennamani is right. There are ways to do things with an array, but it can sometimes get over complicated and unreadable.

Thread Thread
 
davidlazic profile image
David Lazic • Edited

There are still elegant ways to handle that kind of requirement within the function:

  function signIn(user, password) {
    const ALLOWED_USERS = {
      'bob': '',
      'sally': 'gitIsCool7',
      'jerry': 'hackme123',
    };

    return ALLOWED_USERS[user] && ALLOWED_USERS[user] === password || 'Whateva'
  }
Enter fullscreen mode Exit fullscreen mode

And this translated to the initial a and b example becomes:

function example(key, value) {
  const CONFIG_LOOKUP = {
    'a': 10,
    'b': 20,
  };

  return CONFIG_LOOKUP[key] && CONFIG_LOOKUP[key] === value || 'Whateva';
}

Enter fullscreen mode Exit fullscreen mode
Thread Thread
 
coolprofessor profile image
coolprofessor

I see your point, but what if there is a property that is completely unrelated to the other variables? It would be pointless to do it for each one.

function signIn(user,password){
    if( user === 'bob'  && password === '' ){
         return true
    }else if(user === 'sally' && password === 'gitIsCool7#6' && itIsMorning){
         return true
    }else if(user === 'jerry' && password === 'hackme123' && SallyIsOffline){
         return true
    }
}

signIn('jerry','hackme123');
//will return ability to sign in (boolean)
Enter fullscreen mode Exit fullscreen mode
Thread Thread
 
davidlazic profile image
David Lazic • Edited

With lookup maps approach you can drill down how much you wantt with minimal changes to the initial structure, so it would be something like this:

function isMorning () { ... }
function isSallyoffline () { ... }

function signIn(user, password) {
    const ALLOWED_USERS = {
      'bob': {
        pwd: '',
        isValid: () => true,
      },
      'sally': {
        pwd: 'gitIsCool7',
        isValid: () => isMorning,
      },
      'jerry': {
        pwd: 'hackme123',
        isValid: () => isSallyoffline,
      },
    };

    return ALLOWED_USERS[user] &&
           ALLOWED_USERS[user].pwd === password &&
           ALLOWED_USERS[user].isValid() ||
           'Whateva';
}
Enter fullscreen mode Exit fullscreen mode

Now you can go even further and have multiple validity checks for example:

function isMorning () { ... }
function isSallyoffline () { ... }

function signIn(user, password) {
    const ALLOWED_USERS = {
      'bob': {
        pwd: '',
        validation: [
          () => true,
        ],
      },
      'sally': {
        pwd: 'gitIsCool7',
        validation: [
          () => isMorning,
        ],
      },
      'jerry': {
        pwd: 'hackme123',
        validation: [
          () => isMorning,
          () => isSallyoffline,
        ],
      },
    };

    return ALLOWED_USERS[user] &&
               ALLOWED_USERS[user].pwd === password &&
               ALLOWED_USERS[user].validation.every(rule => rule()) ||
               'Whateva';
}
Enter fullscreen mode Exit fullscreen mode

And sorry for jumping in like so in the thread, I just know that plenty of people are for some reason struggling with this approach and I found this example intriguing. Also want to add that there is no practical way to completely avoid if/else statements, I use both approaches in my every day coding, it's just a matter of improving readability and removing code duplication.

If there's a simple 0 and 1 check, I see no reason to use a lookup map for that case, I'd just write down a simple if.

Thread Thread
 
rjitsu profile image
Rishav Jadon

This comment, and example is the best to explain the concept, thanks for this!

Thread Thread
 
naveennamani profile image
naveennamani

@davidlazic are you saying i should replace

a===10
Enter fullscreen mode Exit fullscreen mode


with

example('a', a)
Enter fullscreen mode Exit fullscreen mode


sure those are equivalent, but what above the functionality that i intended to run in the if condition, should I wrap them in anonymous functions and pass to another function. What about the else if condition? Should I call that like

if(example('b', b))

?
If all conditions has some common logic you can use mapping to bring the variability into the object and using the mapped values to execute the logic. But again, even if slight deviation is added (for example a console log in a single else if condition) then your common logic is not common anymore, and you have to add more hacks like anonymous functions as part of the mapping object and so on, as you just demonstrated in your example with validation functions.

The best practical example would be state management in redux, where switch case statements seems to be most efficient, readable and manageable, try implementing that with mapping.

Thread Thread
 
davidlazic profile image
David Lazic

Hey @naveennamani , appreciate the time you've taken to think about this. My comment was a reply, not a statement, where I simply described how a specific problem could be written in a different kind of way with an example. Like I wrote, I use if/else, switch and this kind of approach on every day basis, based on the situation. If a function is supplied with too much logic, there's probably something that's gonna go wrong and it could be split into separate pure parts.

Collapse
 
jimstockwell profile image
Jim Stockwell

Your improved version really is a lot nicer. Thank you for sharing the lesson.

Collapse
 
rjitsu profile image
Rishav Jadon

Thanks a lot for reading!

Collapse
 
phantas0s profile image
Matthieu Cneude

Ah! Sweet coding challenges. I still remember this CTO who wanted me to replace an if else statement using a strategy pattern... the code was 10 lines. How to introduce useless complexity 101.

using multiple if else statements chained together or big switch statements will make your code look very ugly, less readable and error prone.

Why? I mean if it's so ugly, less readable, and error prone, why so many programming language implement them?

Collapse
 
rjitsu profile image
Rishav Jadon

Thanks Michael, yes the comments are filled with useless people just wanting attention. Still thinking about this and surely will provide a better version in the future!

Collapse
 
d3sox profile image
Nico

I agree with what @bubster said. You should rename it to "stop abusing".

Plus I did some benchmarking. It seems like if/else is always the slowest, using a Map makes only a negligible difference in Firefox, and an object is much faster in Chrome. Test for yourself: jsbench.me/jekur7m830/1

(I modified your code a little bit to keep things fair. You called toLowerCase for every branch in the first example and didn't use it in the latter two. I also moved the declaration of the object/Map out of the function, otherwise it would be created for every iteration)

When adding more calls like

whoIsThis('naruto')
whoIsThis('')
Enter fullscreen mode Exit fullscreen mode

to each test case if/else actually wins in Chrome which makes me think if Chrome somehow caches it.

Collapse
 
rjitsu profile image
Rishav Jadon

Oh my bad for not using toLowerCase in further examples! Thanks for the tip about moving the dictionary out of the function.

Collapse
 
bk profile image
BK ☕

You agreed with the tip, but the code example is still not updated. It's better to make the change, so beginners can learn from better examples.

Collapse
 
bk profile image
BK ☕

Btw, my other comment was referring to "Thanks for the tip about moving the dictionary out of the function."

Have a lovely day.

Collapse
 
michaelcurrin profile image
Michael Currin

At large scale a lookup by key is far more efficient. At small scale it is maybe small difference.

If you had extreme case of code of say 1000 branches of if else statements, at worst it takes 1000 attempts until the last one matches.

While looking up a value from an object/map by key is constant - only needed exactly one attempt to find the result.

Collapse
 
andreidascalu profile image
Andrei Dascalu

The first solution is NOT an object-oriented solution. You're using a JS "object" as a poor man's map of sorts but you're not using anything remotely OOP.

Collapse
 
talr98 profile image
Tal Rofe

I don't think replacing "if"/"else if"/"else" conditions with yours is the best.
There is reason we use these known conditions nowadays. It is easy to read. But you are right, it is not always easy to read. I would replace your so-called bad code (the first one of-course) with code which uses only "if" conditions. There is no need to use "else if" when the "if" ones would execute "return" statements.

Collapse
 
codenameone profile image
Shai Almog

The sample above doesn't need else since it returns... That's a pet peeve of mine...

Some comments may only be visible to logged-in visitors. Sign in to view all comments. Some comments have been hidden by the post's author - find out more