DEV Community

Cover image for There's no "else if" in JS
Fabio Russo
Fabio Russo

Posted on • Updated on

There's no "else if" in JS

Grammar is not a joke...

Exactly, in Javascript's grammar there's no else if statement.

How many times have you used it before? Why It's still working?

We always code like this:


function wow(arg){

  if(arg === "dog"){
    return "LOVELY";
  }
  else if(arg === "cat"){
    return "CUTE";
  }
  else return "gimme an animal";
}

wow("cat");
//-> "CUTE"

Enter fullscreen mode Exit fullscreen mode

But what's really happening is this:


function wow(arg){

  if(arg === "dog"){
    return "LOVELY";
  }
  else {
    if(arg === "cat"){
        return "CUTE";
    }
    else return "gimme an animal";
  }
}

wow("cat");

Enter fullscreen mode Exit fullscreen mode

What's happening here?

Literally, we're using some implicit JS behavior about {} uses.

When we use the else if statement we're omitting the {} but Javascript It's still working because It does not requires the parentheses in that case, like in many other cases!

...so what?

I'm not writing this post, just because It's something really curious to know.

I'm writing this to make you think about all the good parts or right ways to code, that forces you to write code in a way, that sometimes It's not really the best way.

There's a lot to discuss about implicit and explicit declaration of stuff like: coercion, parentheses, semicolon...

But the true always stands in the middle!.

If you just follow some specific rules on how to... you're not understanding why those rules were written, and this else if should make you think about It.

How many time have you written code, because someone told you to do so but you were totally blind about It?

I bet, a lot.

I'm not saying that we should not care about ALL those rules, and that we should know ALL the JS documentation.

I'm just saying that right now, your duty is to write good code that can be understood by someone else and to go that way... some rules are ok, but you should know the why.

Because someone is good at code, It does not mean that you have to follow his golden rules.

What's implicit for him, maybe explicit for you and many other people.

If you don't have the same knowledge, about that specific argument (and It's not possible to have exactly the same level of know about It in every single part of the code) you've two options:

  1. Do what he's telling you to do... If It works.
  2. Go out and check the why

Always care about the good parts but first of all, always care about your knowledge and don't code just by rules.

Best-practices must be accepted by many people


think

Oldest comments (98)

Collapse
 
ben profile image
Ben Halpern

Really eye-opening post.

Collapse
 
genta profile image
Fabio Russo

Thanks.
Love to share ideas.
Lots of people think of JS as a β€œbad” language... most of the time, we dunno It.
That’s all.

Collapse
 
ben profile image
Ben Halpern • Edited

JS language + ecosystem is one of the most interesting areas of software these days. "Good or bad", it's probably worth learning the finer details.

Collapse
 
cstroliadavis profile image
Chris

This is a good point, and I think we could write some much longer posts on some of these practices.

I appreciate how this points out how important the "why" is of many of these patterns and practices.

I've been developing in JS since nearly the beginning and many of these "best practices", that are somehow still mainstream, are for problems that no longer exist.

Since people often don't know why we did them, they continue to persist them because all the Sr. Devs told them to years ago.

The "why" is so important to know.

Collapse
 
ben profile image
Ben Halpern

I've been developing in JS since nearly the beginning and many of these "best practices", that are somehow still mainstream, are for problems that no longer exist.

Since people often don't know why we did them, they continue to persist them because all the Sr. Devs told them to years ago.

This is so true of so many areas of software development. Workarounds become best practice and stay that way long after they are needed.

Collapse
 
kayis profile image
K

Only use conditional jumps...wait! xD

Collapse
 
adamdoyle profile image
Adam Doyle

Does anyone know if this is JS-specific or not? Braceless if-statements exist in most languages and now I'm curious if those languages have else-if explicitly defined in their grammars or not.

Collapse
 
joshcheek profile image
Josh Cheek

I believe it's also true for C / C++ / Java. I didn't go check just now, but it has always been my understanding that this was how they worked.

Collapse
 
twigman08 profile image
Chad Smith

Yes, as far as I know this is how a lot of languages, at least most "C-Style language" will do this. You can also look at the grammar of a lot of languages and figure out from there that it would have to do that as else if is not being defined as one keyword. They are separate keywords.

The same is also in python with elif, which j believe is actually just syntatic sugar in the end, and would end up producing the same code.

Collapse
 
mahlongumbs profile image
Mahlon Gumbs

Cool point. In cases like this, I often forgo the else altogether because of the return statements.

function wow(arg){

  if(arg === "dog") return "LOVELY";

  if(arg === "cat") return "CUTE";

  return "gimme an animal";
}

wow("cat");

Still, your point about understanding the why behind what we write is an important one. Thanks for sharing.

Collapse
 
qm3ster profile image
Mihail Malo

A function with only ifs that return is just the missing-from-JS pattern matching+guards syntax.

Collapse
 
mahlongumbs profile image
Mahlon Gumbs

LOL
I guess technically, if statements could have been omitted in this example (though there’d still be a conditional present).

function wow(arg){
  var o = {
    dog: "LOVELY",
    cat: "CUTE"
  };
  return o[arg] || "gimme an animal";
}

wow("cat");
Collapse
 
pranay_rauthu profile image
pranay rauthu • Edited

I think above code needs one more condition.

function wow(arg){
  var o = {
    dog: "LOVELY",
    cat: "CUTE"
  };
  return (o.hasOwnProperty(arg) && o[arg]) || "gimme an animal";
}

wow("cat");

If I want to replace above code. I would do something like this. (with conditions)

const wow = arg => (
  (arg === "dog" && "LOVELY") ||
  (arg === "cat" && "CUTE") ||
  "gimme an animal"
);

wow("cat");
Thread Thread
 
mahlongumbs profile image
Mahlon Gumbs

LOL...nice.

Thread Thread
 
kepler1359 profile image
Kepler1359

can someone explain to me why you can use parathesis instead os curly braces with an arrow function? I was thought that the parathesis are used to indicate to the compiler that what is encapsulated in the parathesis are supposed to be treated as parameters, and what is in the curly braces are supposed to be treated as the logic.

This goes to the point trying to be made by Fabio Russo "the good parts or right ways to code...It's not really the best way."

Thread Thread
 
mahlongumbs profile image
Mahlon Gumbs • Edited

Your information is not incorrect for regular functions. However, with an arrow function, you are allowed to use parentheses to represent a function body with a single statement (useful when spanning multiple lines).

There are other places you can omit things as well.

Examples:

Single parameter, parentheses are optional

const myFunc = (singleParam) => {/* function body */};
// is the same as
const myFunc = singleParam => {/* function body */};

Multiple parameters require parentheses

const myFunc = (param1, param2) => {/* function body */};
const myFunc = param1, param2 => {/* function body */}; //Syntax error due to missing parentheses

Function body needs curly braces for multi-line command block

const myFunc = param1 => {
  console.log('I did something');
  console.log('I did something else');
};

However, if your body is a single line and you want to return the result, you may do any of the following (all of these return the value of name.toUpperCase()

const myFunc = name => {
  return name.toUpperCase(); // note the return
};

const myFunc = name => (
  name.toUpperCase(); // note, no return if in parentheses
);

const myFunc = name => name.toUpperCase();

It really helps if you have a command that spans multiple lines where you just want to return the result. So, for example, if you were dealing with a promise you could do either of the following:

const fetchUser = userId => (
  fetch(`http://example.com/user/${userId}`)
    .then(rsp => rsp.data)
    .catch(error => {
      console.log(error);
    };
);

const fetchUser = userId => {
  return fetch(`http://example.com/user/${userId}`)
    .then(rsp => rsp.data)
    .catch(error => {
      console.log(error);
    };
};
Thread Thread
 
kepler1359 profile image
Kepler1359 • Edited

Now, I understand that you're able to use arrow functions in more diverse ways, but after looking at the code I had trouble with I realize that pranay rauthu used a "hidden if-statement" how does one use the ampersand(&) to make a conditional, and to see if arg === some-value, and print a value based on what the client set arg equal to.

If someone has a response to my question, please point me to some resource so I can deepen my knowledge on javascript

Collapse
 
tunaxor profile image
Angel Daniel Munoz Gonzalez

I gues you would like this piece
hackernoon.com/rethinking-javascri...

Collapse
 
joshcheek profile image
Josh Cheek

-1

Collapse
 
retrazil profile image
Retra Zil

Then why is it there in the language? To put in other words, where does it make sense to use an if-else statement?

Collapse
 
moopet profile image
Ben Sinclair

While I don't agree wth the premise that if is inherently bad in a non-functional programming language, having something in a language doesn't make it good. Many languages are extremely poorly-thought-out and nothing's perfect.

Collapse
 
mnivoliez profile image
mnivoliez

Saying that if-else statement are always bad isn't something I would do. As any other tools, it has to be use in the right place to be effective.
Sometimes, I do prefer a switch (or match expression). But sometimes, it just do not make any sense to avoid the if-else. As an example, when coding a game, you might want to know either or not an object is in front of the player. You will certainly use the dot product as it is cost efficient and then you will have to test if the result is zero or if it is a positive number above zero.
From my point of view, the if-else fits perfectly here. Again, his use has to be cautious.

At least, I think so.

Collapse
 
alephnaught2tog profile image
Max Cerrina

I've never heard that. What's the rationale?

Collapse
 
kayis profile image
K

In FP you could use filter instead of if, which makes your code more modular than stacking if on if.

Collapse
 
joshcheek profile image
Josh Cheek

Another blind gospel: braces around if-statements imply that people don't understand what braces do (they turn a group of statements into a single statement). So rules like "always put braces around the body of your if-statement" get it backwards, it'd be like wrapping every value in an array, because maybe you'll want more than one of them, someday.

This brings us to the the three-brace rule: if you're going to make me put one brace where I don't need it, then I'm going to add two more.

function wow(arg) {{{
  if(arg === "dog") {{{
    return "LOVELY"
  }}} else if(arg === "cat") {{{
    return "CUTE"
  }}} else {{{
    return "gimme an animal"
  }}}
}}}
console.log(wow("cat"))           // => CUTE
console.log(wow("dog"))           // => LOVELY
console.log(wow("hat-log"))       // => gimme an animal

Now, in people's defense, JavaScript's syntax is terrible, it's absurd that this works (when it would be so much more useful to have toplevel objects), and given that it works, it's absurd that you can't drop the braces around function bodies.


And the other super obnoxious mostly un-understood rule: littering semicolons all over the code. Literally after every line that they can, rather than before the ones that cause the problems. It's especially misguided b/c it masks the actual problem lines, and it gives a false implication that omitting the semicolon would mean it continues on the next line. But that isn't true, JS doesn't need a semicolon to terminate the line, only to terminate it early. The reason you stick them at the end is b/c sometimes the next line says "oh hey... Imma tag along with the previous line", so with this dumb rule, every line has to guard against an aggressive next line.

log = text => { console.log("logged: " + text); return log }
log("loggin stuffs")

// and now for some math
(2+2)
(3+3)
Collapse
 
moopet profile image
Ben Sinclair

I agree it's interesting that you can't drop the braces around function bodies (which hadn't occurred to me before) but the example in the post, of where else if ... is actually else { if ... } seems obvious. Isn't that behaving exactly how it's written, and isn't that how everyone would expect it to work if they'd never seen the language before?

Collapse
 
genta profile image
Fabio Russo • Edited

It's not.
Because we're always encouraged to use {} in some ways, and we learn by memory to use those, without knowing the why.
During the first approach to a language, you cannot be so deeply analytic, because you've to trust the rules, or you will never go on.
After the totally beginner phase, you should start to ask yourself the why.

Thread Thread
 
nathank887 profile image
Nathan

Have you ever encountered a bug caused by missing parentheses? Being consistent improves code readability and makes it easier to identify bugs.

Thread Thread
 
genta profile image
Fabio Russo

It's not about... DON'T USE PARENTHESES :D It's all about know the why of parentheses

Thread Thread
 
develcharlie profile image
DevelCharlie

This proves that grammar in JS is a joke!

Collapse
 
genta profile image
Fabio Russo

Now, in people's defense, JavaScript's syntax is terrible, it's absurd that this works (when it would be so much more useful to have toplevel objects), and given that it works, it's absurd that you can't drop the braces around function bodies.

I know what you're talking about.
But do we know, why It's still working?
It's working because of blocks.
You're creating blocks, inside blocks... inside blocks.

That's important in JS, because of the lexical-scope.

I'm not saying that's ok ... I'm just saying that in JS It works like that, not just because It's bad

Collapse
 
joshcheek profile image
Josh Cheek

Apparently I didn't use the word block in there, but yes, I understand this :)

If you want to be really irritated with JS, figure out what's going on with these examples (hint)

$ node -p '{a: {b: 1}}'
1

$ node -p '({a: {b: 1}})'
{ a: { b: 1 } }
Collapse
 
sanderintveld profile image
Sander in 't Veld

Without braces, how would the interpreter / a fellow developer know where the function ends? If you write

function foo(x)
  console.log(x)
console.log("Hello")
foo("Hello")
foo("Hello")

then how often are you expecting to see Hello logged? Three times? Four times? Zero times? An unbounded number of times due to recursion?

Some languages use whitespace or end, but I find the braces to be more readable and less error prone.

Collapse
 
donaldng profile image
Donald Ng

Python developer disagrees. 🐍🐍🐍

Collapse
 
joshcheek profile image
Josh Cheek

I'd expect three times. The function foo(x) would receive the next syntactic element as its body, which is console.log(x). Not because of indentation, but because it's the next expression. If you wanted more than one expression, you would use the braces to make a block, which would group the multiple expressions into one. Then it would be consistent with the way we use blocks on if statements.

Oh, also note that this is how fat arrows work:

const foo = x =>
 console.log(x)
console.log("Hello")
foo("Hello")
foo("Hello")
Collapse
 
cmelgarejo profile image
Christian Melgarejo

If you have lots of else ifs then start using switch

Collapse
 
cmelgarejo profile image
Christian Melgarejo • Edited

(I hope you see what I did there)

Collapse
 
jochemstoel profile image
Jochem Stoel

What exactly did you do there, Christian?

Thread Thread
 
cmelgarejo profile image
Christian Melgarejo

used just one if :P

Collapse
 
poooky5 profile image
Pooky

I saw it, nicely done

Collapse
 
alainvanhout profile image
Alain Van Hout • Edited

Why not switch by default, just in case? ;-)

Collapse
 
slumboy profile image
slumboy • Edited

try node.js and es6
example

Collapse
 
mahlongumbs profile image
Mahlon Gumbs

I would use const instead of var though (if you're gonna go es6).

And just for shits and giggles, the fn could be done as a one-liner:

const wow = arg => ({dog: "LOVELY", cat: "CUTE"}[arg] || "gimme an animal");
wow("cat");
Collapse
 
slumboy profile image
slumboy

Cool

Collapse
 
tohodo profile image
Tommy

Thanks for the write-up. This kinda reminds me of that beginner's guide to shell scripting article that opened our minds to the fact that when we use if brackets in bash we're actually using test ;).

Collapse
 
flexdinesh profile image
Dinesh Pandiyan

Whoa! Mind=Blown.

I'm a huge fan of else if. I used it at least 5 times today alone.

Collapse
 
jbeetz profile image
J Beetz

Great article! I especially like the last part. Always care about your knowledge -my emphasis. Very good point! It is easy to follow along, it is hard to know why. Knowing the why is the best part!

Collapse
 
genta profile image
Fabio Russo

Knowing the why... should be the why we love to code!