Ifs Are Good, But Ternaries Might Be Better

January 30, 2018 0 Comments

Ifs Are Good, But Ternaries Might Be Better

 

 

There are a couple of areas we as developers could improve our JavaScript code by dropping if and switch statements and using ternaries instead. Allow me to demonstrate!

When doing conditional assignment, use ternaries. So instead of:

let result
if (operator = ‘+’) {
result = left + right
} else if (operator
= ‘’) {
result = left * right
} else if (operator = ‘-’) {
result = left — right
} else {
result = left / right
}

Do:

const result =
operator = ‘+’ ? left + right
: operator = ‘
’ ? left * right
: operator = ‘-’ ? left — right
: left / right
  • Less code.
  • Prefers constover let. (See Eric Elliot on why we should do this.)
  • Avoids side effects (i.e. assigning value of variable outside block scope).

Similar to a key-value map, we map one condition to one return value on each line.

Ternaries are designed to return a value, and if you can use them for variable assignment, that’s great! But sometimes you need a control structure for conditional execution of code to perform side effects, and ternaries can help here, too. Instead of:

if (conditionA) {
outcome1()
} else if (conditionB) {
if (conditionC) {
outcome2()
} else {
outcome3()
}
} else {
outcome4()
}

Do:

conditionA ? outcome1()
: conditionB && conditionC ? outcome2()
: conditionB ? outcome3()
: outcome4()

Again, less code.

Notice also that in this case our ifs were nested, but we refactored our ternary for less cognitive load. With nested logic, we must be aware of the inner context and each outer context. Although this is a “nested ternary”, we don’t have to use nested thinking. Since each line has a single condition and outcome, in practice you can focus on one line at a time. Once you’ve ruled out a prior condition you can safely ignore it. We could have done this with our if as well:

if (conditionA) {
outcome1()
} else if (conditionB && conditionC) {
outcome2()
} else if (conditionB) {
outcome3()
} else {
outcome4()
}

It’s better than before! But again, the ternary form is terser. Less to read, and less to maintain.

(Notice that this refactor to reduce cognitive load also applies to conditional assignment, or anywhere you are using nested logic which would lend itself to refactoring in this way.)

Of course, you could also use switch for your conditional assignment and your side effects:

let result;
switch (operator) {
case '+':
result = left + right
break
case '*':
result = left * right
break
case '-':
result = left - right
break
default:
result = left / right
}
...
switch (true) {
case conditionA:
outcome1()
break
case conditionB && conditionC:
outcome2()
break
case conditionB:
outcome3()
break
default:
outcome4()
}

But again, we have more code, meaning more to read and maintain, and there’s also more surface area in which bugs can hide — bugs such as the ones you’ll get when forgetting to include the break statement on each case except the default. And we’re still using let to assign a variable outside the block scope.

I hope I’ve convinced you that there is ample opportunity to improve our code with the use of ternaries. If not, let me know why in the comments!

This article was inspired by Eric Elliott’s Nested Ternaries are Great.


Tag cloud