You’re likely already familiar with the ternary operator, how it takes three operands and is often used to create one-liners that would otherwise take multiple lines to write. There are other constructs that cleverly emulate the ternary operator. I’ll show the few that I know of here, but first lets start with an example that we’ll reduce to a ternary and then to the aforementioned ternary-esque patterns.

Each example below can be copied/pasted into your browser’s console so you can see the expected results.

Classic Ternary Example

Take this normal if/else block:

var foo = 'bar', str; // declare variables
if (foo === 'bar'){
   str = 'foobar';
} else {
   str = 'foo';
}
console.log(str); // foobar

The if block takes quite a few lines of code. By using the ternary operator we can shorten it to a single line. The ternary operator takes the following form:

condition ? expr1 : expr2

… which is to say, if the condition evaluates to “true” then return expr1 else return expr2.

Using the above we can turn our if example into this:

var foo = 'bar', str; // declare variables
str = foo === 'bar' ? 'foobar' : 'foo'; // use a ternary operator
console.log(str); // foobar

Simple enough, lets look at two examples that emulate the ternary operator, the first one is below…

Ternary-esque Short Circuit Expression

condition && (expr1) || (expr2)

This is not a ternary but rather an expression that takes advantage of operator precedence which first evaluates the expression to the left of the logical AND operator &&. If the left side is true then the right side of the logical AND will be evaluated next. The parenthesis forces the interpreter to first evaluate the contained expression for truthiness which is how we trick it to execute our code (see this example) – but of course in this case we just have a string. If the first expression is false (incidentally an error in exp1 will be falsey) then the expression to the right of the logical OR operator || is evaluated instead.

This is how our initial if statement looks using this pattern:

var foo = 'bar', str; // declare variables
str = foo === 'bar' && ('foobar') || ('foo');
console.log(str); // foobar

Ternary-esque Object Literal Using a Boolean Key

Here’s another ternary-esque example – this is an object literal treated as an associative array constructed in such a way that it behaves much like a ternary. It first constructs said object so that it has two properties, true and false and assigns string values to them. Next, via the array literal short-hand (brackets) it attempts to access either one of the properties via an expression that must return “true” or “false”. Either one of those values will function as the key to one the object’s properties (‘true’ or ‘false’) and return its value:

{false: expr2, true: expr1}[condition]

var foo = 'bar', str; // declare variables
str = {false:'foo',true: 'foobar'}[foo === 'bar'];
console.log(str); // foobar

Ternary-esque Array Literal with a Boolean-Converted Integer Index

This example makes use of the unary operator  +  to convert boolean true/false to the integers 1 or 0. For example:

console.log(+true); // returns 1
console.log(+false);// returns 0

We can replace the boolean with an expression:

console.log(+('cat' === 'cat')); // returns 1

The conversion of a boolean to an integer allows us to use the evaluated expression as an array index:

var foo = 'bar', str; // declare variables
str = ['foo','foobar'][+(foo === 'bar')];
console.log(str); // foobar

Another way to convert the boolean to a number (or any number in string form for that matter) is to use the double NOT bitwise operator:

console.log(~~true); // returns 1
console.log(~~false);// returns 0

Nesting Ternary Operators

What discussion about ternary operators would be complete without talking about nesting them? Its true you can do this and yes some people find it hard to read and in fact almost everybody rails against the practice. Lets review an example:

var countrycode = 'eu';
var audience = (countrycode == 'eu')?'audienceEU':(countrycode == 'jp')?'audienceJP':(countrycode == 'cn')?'audienceCN':'audienceUS';
console.log(audience); // audienceEU

What we see here is that if the first expression is evaluated as being “false” then the first nested ternary operator is evaluated. If its expression is false, then we go to the next ternary and so on until we reach the end. If the last nested ternary operator is reached and its expression is also false then audience must be ‘audienceUS’. Of course, it doesn’t get that far because in the above code sample the first expression proves to be true.

IMO its not all **that** confusing to read, but its certainly could be challenging for others to make sense of especially if one attempts to nest something more complicated than what is shown here.

However, if we add some whitespace the result is much easier to understand (portions of this code sample has been lifted from StackOverflow and I noticed that John Resig formatted a nested ternary the same in a 2012 forum post):

var countrycode = 'eu';
var audience = (countrycode == 'eu') ? 'audienceEU' :
               (countrycode == 'jp') ? 'audienceJP' :
               (countrycode == 'cn') ? 'audienceCN' :
               'audienceUS';
console.log(audience); // audienceEU

To my eyes the above is very readable. If we were to write it like this would there still be objections as to its use? I honestly don’t think so.

Looking at the above sample I think its quite clear that if the condition on the left is true, then the expression on the right is assigned. If the condition is false then we move to the next line and so on.

Emulating Nested Ternary Operators with Switch Statements

FWIW I think the added whitespace formatting makes the previous example look very similar to the following switch statement:

var countrycode = 'eu';
var audience;
switch(countrycode ) {
     case 'eu': audience = 'audienceEU'; break;
     case 'jp': audience = 'audienceJP'; break;
     case 'cn': audience = 'audienceCN'; break;
     default  : audience = 'audienceUS';
}
console.log(audience); // audienceEU

It may be a stretch to call the above switch statement a nested ternary-esque construct but if you’ll permit me to say so, I think it certainly **resembles** a series of nested ternary operators what with its waterfall of conditional expressions and then the final “default” value. (Yes, I did put the break statement on the same line to more closely resemble the nested ternary example 😉 )

If you use switch statements in your work you can see that you can save a little bit of code by using the whitespace-formatted nested ternary approach. Of course, it all depends on what you’re doing as these examples are simple enough to lend themselves to the discussion.

Emulating Nested Ternary Operators with Short Circuit Evaluation

As we get further away from the ternary pattern and closer to the constructs that mimic or resemble it (however vaguely) we would be remiss not to revisit in more detail the topic of short circuit evaluation via the use of the logical OR || and logical AND && operators.

First, as you may have surmised from the previous short circuit example, the logical OR operator takes this form:

expr1 || expr2

We can use logical OR to create expressions that have a fallback, for example, if the expression on the left of the operator is truthy then evaluation of the entire expression stops there. If it happens to be falsey, then what is to the right of the operator is evaluated instead. Its use essentially allows us to set a default value such as in the next example.

var audience = audience || ”;

Basically, if audience doesn’t exist then assign the empty string else assign audience to itself. Lets see this in its ternary form:

var audience = audience ? audience : ”;

Next, the logical AND operator && takes this form:

expr1 && expr2

Unlike the logical OR where if the left side is falsey then the right side is evaluated, the logical AND can be used to evaluate both sides of the operator. In the application of it in these final examples – the left side must be true in order for the right side to be evaluated. You will see here that we are grouping expressions to be evaluated for truthiness and that we are using a little trick to assign the right side of the operator if the left side happens to be true. Note how we can take advantage of it to do something like this:

var countrycode = 'eu';
var audience = (countrycode == 'eu') && ('audienceEU');
console.log(audience); // audienceEU

Its important to note that if the expression on the left evaluates to false then audience would be boolean “false”;

Can we represent this as a ternary operator? Yep:

var countrycode = 'eu';
var audience = countrycode == 'eu' ? 'audienceEU' : false;
console.log(audience); // audienceEU

Finally lets apply the idea of short circuit evaluation to the nested ternary example:

var countrycode = 'eu';
var audience = (countrycode == 'eu') && ('audienceEU') ||
               (countrycode == 'jp') && ('audienceJP') ||
               (countrycode == 'cn') && ('audienceCN') ||
               ('audienceUS');
console.log(audience); // audienceEU

Nesting Review

I think its useful to review the original nested ternary against the constructs that serve to accomplish the same thing, so here they are:

Nested Ternary Operators

var countrycode = 'eu';
var audience = (countrycode == 'eu') ? 'audienceEU' :
               (countrycode == 'jp') ? 'audienceJP' :
               (countrycode == 'cn') ? 'audienceCN' :
               'audienceUS';
console.log(audience); // audienceEU

Emulating Nested Ternary Operators with a Switch Statement

var countrycode = 'eu';
var audience;
switch(countrycode ) {
     case 'eu': audience = 'audienceEU'; break;
     case 'jp': audience = 'audienceJP'; break;
     case 'cn': audience = 'audienceCN'; break;
     default  : audience = 'audienceUS';
}
console.log(audience); // audienceEU

Emulating Nested Ternary Operators with Short Circuit Evaluation

var countrycode = 'eu';
var audience = (countrycode == 'eu') && ('audienceEU') ||
               (countrycode == 'jp') && ('audienceJP') ||
               (countrycode == 'cn') && ('audienceCN') ||
               ('audienceUS');
console.log(audience); // audienceEU

Emulating Nested Ternary Operators with a Ternary-esque Object Literal Using a Boolean Key

You might ask yourself why I mentioned a “Ternary-esque Object Literal Using a Boolean Key” but didn’t attempt to use that pattern in a “nested” fashion. I didn’t bother because I knew it would be too complex for everyday use. However, if you really want to see what that would look like then here it is, formatted to be as close to the above three examples as possible – I’m not advocating this approach – its just here for illustrative purposes!!!

// Don't do this unless your intent is to confuse people 😉
var countrycode = 'eu';
var audience =  {
   true: 'audienceEU', false:{
      true: 'audienceJP', false:{
         true: 'audienceCN', false:{
            true: 'audienceJP', false:'audienceUS'
            }[countrycode === 'jp']
         }[countrycode === 'cn']
      }[countrycode === 'jp']
   }[countrycode === 'eu'];
console.log(audience); // audienceEU

Emulating Nested Ternary Operators using an Array Literal with a Boolean-Converted Integer Index

The same nesting approach applied to the idea of using the unary operator to convert booleans to integer 1 or 0 to display the corresponding array index – not as confusing as I thought it would be but still not a pattern worth using.

// another confusing pattern....
var countrycode = 'eu'
var audience = [[['audienceUS',
                  'audienceCN'][+(countrycode == 'cn')],
                  'audienceJP'][+(countrycode == 'jp')],
                  'audienceEU'][+(countrycode == 'eu')]
console.log(audience); // audienceEU

// lets try different country codes
var countrycode = 'xyz'; // bad code
var audience = [[['audienceUS',
                  'audienceCN'][+(countrycode == 'cn')],
                  'audienceJP'][+(countrycode == 'jp')],
                  'audienceEU'][+(countrycode == 'eu')]
console.log(audience); // audienceUS << this is the fallback value

// try another countrycode
var countrycode = 'cn'
var audience = [[['audienceUS',
                  'audienceCN'][+(countrycode == 'cn')],
                  'audienceJP'][+(countrycode == 'jp')],
                  'audienceEU'][+(countrycode == 'eu')]
console.log(audience); // audienceCN