I don't know if you've ever encountered an if-else nesting like a pyramid placed horizontally:
if (true) {
}
if (true) {
}
if (true) {
if (true) {
if (true) {
}
} else {
}
} else {
}
If there are too many if-else in a piece of code, the readability of the code will drop rapidly, it becomes very difficult to maintain the code later on.Next I will talk about how to remove them.
Conditional operator
For the simpler if-else statements, they can easily be rewritten as conditional operators:
// Bad π₯
if (true) {
console.log("Congratutions!")
} else {
console.warn("Oops, something went wrong!")
}
// Great π₯°
true
? console.log("Congratutions")
: console.warn("Oops, something went wrong!")
Of course, at this point the difference between the two is not that great.
Logical AND operator
If you just want to execute a function when a certain condition is met, then you can use logical AND operator:
if (true) {
alert(1)
}
// is equals to:
true && alert(1)
It has very strict conditions of use, only functions can be executed and no statements can be used, including "return". This doesn't make the code look more logical though, but it can be useful in certain cases.
Early returns
Metioned by @Edenn Touitou and @Infinite Table.
Just sort the conditions by their complexities and return each time:
function handleRequest(req) {
if (req.code >= 500) {
return "Server error";
}
if (req.code >= 404) {
return "Cilent error";
}
return "Suceess";
}
Table driven method
For code like the following, most of the time we will use switch instead. But it's not the best solution, and if we forget to add "break;", the code may run beyond expectations, and switch is not very elegant.
// Bad π₯
const weekday = (num) => {
if (num === 1) {
return "Monday"
} else if (num === 2) {
return "Tuesday"
} else if (num === 3) {
return "Wednesday"
} else if (num === 4) {
return "Thursday"
} else if (num === 5) {
return "Friday"
} else if (num === 6) {
return "Saturday"
} else if (num === 7) {
return "Sunday"
} else {
return "Unknown"
}
}
console.log(weekday(1)) // Monday
This is the time to use the table driven method:
// Great π₯°
const weekday = (option) => {
let obj = {
1: "Monday",
2: "Tuesday",
3: "Wednesday",
4: "Thursday",
5: "Friday",
6: "Saturday",
0: "Sunday"
}
return obj[option] ?? "Unknown"
}
console.log(weekday(1)) // Monday
Or you can use ES6's Map:
// Great π₯°
const weekday = (num) => {
const map = new Map()
.set(1, "Monday")
.set(2, "Tuesday")
.set(3, "Wednesday")
.set(4, "Thursday")
.set(5, "Friday")
.set(6, "Saturday")
.set(7, "Sunday");
return map.has(num) ? map.get(num) : "Unknown";
};
console.log(weekday(1));
Array's include method
In the previous section, we discussed how to optimize one-to-one selection structures, and here we discuss how to elegantly implement one-to-many selection structures.
For example, the following script:
const getContinent = (option) => {
if (option === "China" || option === "Japan") {
return "Asia";
}
if (option === "Germany" || option === "France") {
return "Europe";
}
};
console.log(getContinent("China"));
It doesn't look that bad now because I haven't added all the countries in yet. This is certainly optimizable and can be easily avoided by using Array's include method:
const getContinent = (option) => {
const Asia = ["China", "Japan"];
const Europe = ["Germany", "Franch"];
if (Asia.includes(option)) return "Asia";
if (Europe.includes(option)) return "Europe";
return "Unknown";
};
console.log(getContinent("China")); // Asia
After this optimization, the code will not become cluttered even if more countries are added. But it can get even better:
const getContinent = (option) => {
let [result, setResult] = ["unknown", (str) => (result = str)];
const Asia = ["China", "Japan"];
const Europe = ["Germany", "Franch"];
Asia.includes(option) && setResult("Asia");
Europe.includes(option) && setResult("Europe");
return result;
};
console.log(getContinent("China"));
Conclusion
From this article, we have learned how to reduce if-else in your code. If you think this post is helpful, please share it with your network, if you have comment, drop them anywayπ.
Top comments (15)
Simple thing to reduce the size and complexity of if-else loops : fail-fast.
You sort the conditions by their complexities and return each time. For example in place of writing :
Write something more like this :
Code is less cluttered by unnecessary else-if and you understand better the goal of the function
Unpopular opinion: this structure is far from ideal for readability.
Before going any further, I want to mention that I 100% agree with the fail-fast methodology. You should always do that, but not at the cost of readability.
1 - Alphabetical order
Response statuses, or any
code
, should be in alphabetical order.It's much easier to read when the
code
s are top -> down in a chronological order.Trying to optimize execution time is totally pointless, you're not even gonna save
1 ms
while going against any logical search pattern with your eyes...If I need to
CTRL + F
orCMD + F
to figure out which status is where, readability is 0%.2 - Line indentation
Indentation improves readability a thousand fold.
Flattening your structure means you now have an
implicit
relationship with yourif
s.Given your eyes will scan top -> down first, then left -> right (assuming english), the
if / else if / else
pattern will give youimmediate
andexplicit
relationships between all the elements of your code.3 - Multiple returns
Oh my, the most unpopular opinion ever...
Using multiple
return
in a function will force you to scan the whole code to figure out theexit
points. The burden is put on the reader to map every single outcome by himself.When using multiple
return
, every singleif
becomes a potential trap the dev could fall into and make a mistake. You absolutely need to scan all the code to figure out if the next block of code will be executed or not because at any point the eject button could be pressed.If you use only 1
entry
point and 1exit
point, you know by simply scanning top -> down that the next block of code will always be executed. All you have to do is follow indentation, theif / else if / else
brackets and the whole outcome map will be laid out for you. You don't have to do any mental gymnastic, it's simple and you should very rarely make mistakes.4 - Eye pattern
Just take a glance at those 2 patterns:
Or
At a glance, can you tell me with 100% certainty that conditions in pattern
A
are mutually exclusive?How about in pattern
B
?With pattern
A
, you simply cannot know without any doubt the nature of those conditions. Maybe they're mutually exclusive, maybe they all apply, maybe it's anything in between.With pattern
B
, you don't even have to know what's written, just look at the brackets and the indentation and you already know those conditions are mutually exclusive. Even after replacing every single letter byx
, the meaning is still there and the pattern is still obvious.Conclusion
I know a lot of people will go completely banana against this opinion. It's fine, I'm used to it.
All I'm gonna say is people need to take into account accessibility and readability. Both of which won't prevent you from
failing fast/early
and they won't impact performance in the slightest. There's really no reason to not account for them.This is indeed very useful, I forgot when I was writing it, I will add it in the next article revision
THANK YOU. I wanted to write this exact thing but you came first
I think table driven method should be must to teach during introductory teaching of programming fundamentals, students take these bad writing style along with them which is easy to spot on their code base. Sad thing is even most teacher which I've experienced aren't aware of that.
No. Please, no. Map lookups are such a silly shorthand, and more often than not they're just replacing a different structure designed for this purpose:
switch/case
.Please stop telling people to use map lookups as if code golf is our goal.
Yeah, sometimes I really wish my classmates would work on how to write beautiful code.
Maybe it's only me, but
or
is easier to read and understand then
I thought so too, but many books claim that this style is not clear enough and could be misleading, so I didn't include it in the article
I completely agree. Besides that I learned something new about the very shorthand syntax, Iβd always prefer the second one.
if the conditions are exclusive, I find early returns to be a very useful way of organising code:
one more for the list
that could be used with tuples
[() => false, () => 'some value']
, with default values (setting the last item condition to return alwaystrue
), etc..I swear if i had a dollar for every minute i spend fixing when i used conditional operator wrong, I'd probably be a millionaire by now.
For some reason I always use it wrong and then wonder why. Then after half an hour I'm like 'oh!' π
Nice article btw, liked, bookmarked, unicorned. Clicked on every button I could see so i could always save some time from now on π
you should try golang
Coincidentally, I'm about to learn golangπ