Well, I write this article because lately I was dealing with source code in js that had an excessive amount of if statement,
at levels that I had never seen. That is why I think it is very important to share these simple techniques that will help us to write code without having to think about the "if" when deciding.
I am going to explain 6 ways on how to do this. The idea of this is not to enter into paranoia of never using IF, it is to open the head to new ways of thinking about our decisions in JS.
Categories:
- Ternary operator
- Short circuit
- Function delegation
- Non-branching strategie
- Functions as Data
- Polymorfism
1) Ternary operator:
We are talking about this "condition ? expr1 : expr2", very easy.
Example 1:
- Code with IF:
function saveCustomer(customer) {
if (isCustomerValid(customer)) {
database.save(customer)
} else {
alert('customer is invalid')
}
}
- Refactored code:
function saveCustomer(customer) {
return isCustomerValid(customer)
? database.save(customer)
: alert('customer is invalid')
}
- ES6 style:
const saveCustomer = customer =>isCustomerValid(customer)?database.save(customer):alert('customer is invalid')
Example 2:
- Code with IF:
function customerValidation(customer) {
if (!customer.email) {
return error('email is require')
} else if (!customer.login) {
return error('login is required')
} else if (!customer.name) {
return error('name is required')
} else {
return customer
}
}
- Refactored code:
// ES6 style custom formatted ternary magic
const customerValidation = customer =>
!customer.email ? error('email is required')
: !customer.login ? error('login is required')
: !customer.name ? error('name is required')
: customer
Example 3:
- Code with IF:
function getEventTarget(evt) {
if (!evt) {
evt = window.event;
}
if (!evt) {
return;
}
const target;
if (evt.target) {
target = evt.target;
} else {
target = evt.srcElement;
}
return target;
}
- Refactored code:
function getEventTarget(evt) {
evt = evt || window.event;
return evt && (evt.target || evt.srcElement);
}
2) Short circuit:
It is a technique that uses the AND and OR operators to evaluate expressions.
https://codeburst.io/javascript-short-circuit-conditionals-bbc13ac3e9eb
true || true;
// true
true || false;
// true
false || false;
// false
Example 1:
- Code with IF:
const isOnline = true;
const makeReservation= ()=>{};
const user = {
name:'Damian',
age:32,
dni:33295000
};
if (isOnline){
makeReservation(user);
}
- Refactored code:
const isOnline = true;
const makeReservation= ()=>{};
const user = {
name:'Damian',
age:32,
dni:33295000
};
//Apply the short circuit to avoid the if.
isOnline&&makeReservation(user);
Example 2:
- Code with IF:
const active = true;
const loan = {
uuid:123456,
ammount:10,
requestedBy:'rick'
};
const sendMoney = ()=>{};
if (active&&loan){
sendMoney();
}
- Refactored code:
const active = true;
const loan = {
uuid:123456,
ammount:10,
requestedBy:'rick'
};
const sendMoney = ()=>{};
//Apply short circuit in this case, the loan is evaluated true because !=undefined
active && loan && sendMoney();
3) Function delegation:
This technique mix the short circuit and separation code block with functions.
Example 1:
- Code with IF:
function itemDropped(item, location) {
if (!item) {
return false;
} else if (outOfBounds(location) {
var error = outOfBounds;
server.notify(item, error);
items.resetAll();
return false;
} else {
animateCanvas();
server.notify(item, location);
return true;
}
}
- Refactored code:
function itemDropped(item, location) {
const dropOut = function() {
server.notify(item, outOfBounds);
items.resetAll();
return false;
}
const dropIn = function() {
server.notify(item, location);
animateCanvas();
return true;
}
return !!item && (outOfBounds(location) ? dropOut() : dropIn());
}
4) Non branching strategy:
This technique try to avoid the use of switch statemente. The idea is to create a map with keys/values and using a function
to access the value of the key passed as parameter.
The idea came from this link: https://medium.com/chrisburgin/rewriting-javascript-replacing-the-switch-statement-cfff707cf045
Example 1:
- Code with SWITCH:
switch(breed){
case 'border':
return 'Border Collies are good boys and girls.';
break;
case 'pitbull':
return 'Pit Bulls are good boys and girls.';
break;
case 'german':
return 'German Shepherds are good boys and girls.';
break;
default:
return 'Im default'
}
- Refactored code:
const dogSwitch = (breed) =>({
"border": "Border Collies are good boys and girls.",
"pitbull": "Pit Bulls are good boys and girls.",
"german": "German Shepherds are good boys and girls.",
})[breed]||'Im the default';
dogSwitch("border xxx")
5) Functions as Data:
We know that in JS the function are first class, so using it we can split the code into a function objects.
Example 1:
- Code with IF:
const calc = {
run: function(op, n1, n2) {
const result;
if (op == "add") {
result = n1 + n2;
} else if (op == "sub" ) {
result = n1 - n2;
} else if (op == "mult" ) {
result = n1 * n2;
} else if (op == "div" ) {
result = n1 / n2;
}
return result;
}
}
calc.run("sub", 5, 3); //2
- Refactored code:
const calc = {
add : function(a,b) {
return a + b;
},
sub : function(a,b) {
return a - b;
},
mult : function(a,b) {
return a * b;
},
div : function(a,b) {
return a / b;
},
run: function(fn, a, b) {
return fn && fn(a,b);
}
}
calc.run(calc.mult, 7, 4); //28
5) Polymorphism:
Polymorphism is the ability of an object to take on many forms. The most common use of polymorphism in OOP occurs when a parent class reference is used to refer to a child class object.
Example 1:
- Code with IF:
const bob = {
name:'Bob',
salary:1000,
job_type:'DEVELOPER'
};
const mary = {
name:'Mary',
salary:1000,
job_type:'QA'
};
const calc = (person) =>{
if (people.job_type==='DEVELOPER')
return person.salary+9000*0.10;
if (people.job_type==='QA')
return person.salary+1000*0.60;
}
console.log('Salary',calc(bob));
console.log('Salary',calc(mary));
- Refactored code:
//Create function to different behaviour, same parameter call.
const qaSalary = (base) => base+9000*0.10;
const devSalary = (base) => base+1000*0.60;
//Add function to the object.
const bob = {
name:'Bob',
salary:1000,
job_type:'DEVELOPER',
calc: devSalary
};
const mary = {
name:'Mary',
salary:1000,
job_type:'QA',
calc: qaSalary
};
//Same call.
console.log('Salary',bob.calc(bob.salary));
console.log('Salary',mary.calc(mary.salary));
Readings:
A list of interesting links about this same topic.
- https://www.google.com/amp/s/javascriptweblog.wordpress.com/2010/07/26/no-more-ifs-alternatives-to-statement-branching-in-javascript/amp/
- http://adripofjavascript.com/blog/drips/using-duck-typing-to-avoid-conditionals-in-javascript.html
- https://hackernoon.com/rethinking-javascript-the-if-statement-b158a61cd6cb
- https://stackoverflow.com/questions/57023787/descending-order-with-if-else-and-not-use-logical-operators-javascript
- https://medium.com/front-end-weekly/javascript-path-to-eliminating-if-else-dab7a1912024
- https://medium.com/edge-coders/coding-tip-try-to-code-without-if-statements-d06799eed231
Visit my github for more projects!!
https://github.com/damiancipolat?tab=repositories
Latest comments (47)
Most of the suggestions will just make your code a nightmare to maintain. This is the opposite of clean code. If someone want better code he should not use tricks like that. Good luck reading your code that was written few years ago, I only hope that it will not be someone that new into programming.
Nested ternaries? Yuck.
Hi, thank you for writting. As a lot of people say, sometimes is not readable, always think readability and the most important, think for the others, junior devs and so one :)
Have a nice day!
ESLint discourages the use of nested ternary conditions.
It's the problem you are letting the lint tell you how you have to program. eslint can be configured by activating and deactivating rules to suit each one.
Q. Who wrote the linter rules?
A. People with enough experience to know that nested ternaries are really difficult for a human to parse quickly and therefore make code difficult to work with.
Very nice article. But I think I found one catch:
The rewrite in the second example for ternary operators makes the code very unreadable. The cumbersome part of this example are the
else
statements. If you use guard clausesif
statements, the code becomes much more readable and concise:In this case, you can even remove the curly braces:
Now both versions are much more readable and the reader can understand the intent of the written code much better: catch errors and return them.
thanks for comment!
Hey Damian the last example is not working.
the output is:
:o :O yes that true, I will fix it. thanks for tell me.
Maybe add a señority level indicator before star reading the article.
The article is nice, it gives some cool alternatives that not everyone might know about, a handful of which we use at work.
As others said, tho, some are harder to read.
A little side note about #4 and #5: it would be better to re-use the object and not to create it every time a function is called (eg: creating it inside
array.map()
, etc), it slows down your code a lot!I'm saying this because it might not be obvious and also because I've had to refactor some code that was doing the exact same thing after I got hired 😊
A better approach would be to do something like this instead:
If you want even better performance out of this, you can use a Map() instead of an object 🖖🏼
Edit: I think you have two #5s 🤔
thanks for comments! the idea was make an arrow function that return an object. I had thought about this option too, it is more semantic but much more code. It is in each developer as you feel more comfortable.
thanks, you're open my world :DDD
Hi @damxipo !
I'm a ternary fan, but as many said, those nested ternaries are harder to read than the ifs.
I really liked the switch alternative, I'm going to implement it right now.
Please, pleeease, change those vars to let/const :)
Thanks Damian, really good article! Keep it coming
Oh my god is true, my bad. I always use let and I don't know what happened
TBH I think all of your examples are more readable with ifs, especially the nested ternaries. I would hate to see that in code I have to work with.
Ifs are very easy to read and understand, there is no performance problems with them. What do you gain from avoiding ifs?
I didn't know that was possible to create a arrow function that returns a object's property that was just created in time. Nice
I've had to deal with "overdone" uses of the ternary operator. I was not pleased.
The point of replacing the elseif with ternary nesting is hard to read. Another way could be to use a single level of if. but the idea of the article was to program without using a single if. I am open to see other devs as they would raise this.
Some useful suggestions here; but some should come with health warnings:
false
when another type is expected (this is a good use for ternary). Linting rules often disallowconditionIsTrue && functionCall()
outside an assignment expression.if
but can get rid of the redundant use ofelse
. Simpler and more readable than your suggestion.I totally agree that nested ternaries are a pain to read.
Also, the itemDropped sample looks very "magical" to a person not familiar with such paradigm.
Well the idea is to provide reason to star going deeper in JS.
The nested ternary hurts my brain, despite that, the article has a lot of gems, thanks guys!
hahaha yes is hard to process I know, but are just examples, the idea is to open the brain to new alternatives some very nice other heavy to understand.
I am glad to see that it generates reactions in other devs, it is the idea of the article. As I said above, the idea is not to stop using if it's just something to shake them and they can think about decisions in another way.
Generating reactions is all well and good, but I think it would be more productive to put forward examples of alternatives to
if
in contexts where they are appropriate/useful. Given the introduction describing code with too many ifs; some junior devs may mistakenly believe all your solutions represent good practice...In the header it says that they are clearly techniques and you should not go into paranoia. Maybe in future articles I will raise 'real' situations I am collecting many situations with many sentences of my work, but at the moment I do not have enough time to do something at that level.
While you've shown some nice alternatives for IF, most of these examples feel less readable after being refactored. Especially chaining the ternary operator should be avoided IMHO.
Yes in the refactor, some of semantic is lost. The chaining ternaries is the most extreme. Consider this things as example you can chose use it or not.
Some comments may only be visible to logged-in visitors. Sign in to view all comments.