116

I know you can set variables with one line if/else statements by doing var variable = (condition) ? (true block) : (else block), but I was wondering if there was a way to put an else if statement in there. Any suggestions would be appreciated, thanks everyone!

1

11 Answers 11

271

Sure, you can do nested ternary operators but they are hard to read.

var variable = (condition) ? (true block) : ((condition2) ? (true block2) : (else block2))
Sign up to request clarification or add additional context in comments.

3 Comments

Yeah, in this case if() { ... } else if() { ... } else { ... } is probably more readable.
Any ternary operators are hard to read. They're terse and not descriptive. Even non programmers have an idea what if () else () might mean.
Hard to read... unless you use line breaks and indents properly, then it can be quite easy.
67

tl;dr

Yes, you can... If a then a, else if b then if c then c(b), else b, else null

a ? a : (b ? (c ? c(b) : b) : null)

a
  ? a
  : b
      ? c
        ? c(b)
        : b
      : null

longer version

Ternary operator ?: used as inline if-else is right associative. In short this means that the rightmost ? gets fed first and it takes exactly one closest operand on the left and two, with a :, on the right.

Practically speaking, consider the following statement (same as above):

a ? a : b ? c ? c(b) : b : null

The rightmost ? gets fed first, so find it and its surrounding three arguments and consecutively expand to the left to another ?.

   a ? a : b ? c ? c(b) : b : null
                 ^                  <---- RTL
1.            |1-?-2----:-3|
             ^ <-
2.        |1-?|--2---------|:-3---|
     ^ <-
3.|1-?-2-:|--3--------------------|

result: a ? a : (b ? (c ? c(b) : b) : null)

This is how computers read it:

  1. Term a is read.
    Node: a
  2. Nonterminal ? is read.
    Node: a ?
  3. Term a is read.
    Node: a ? a
  4. Nonterminal : is read.
    Node: a ? a :
  5. Term b is read.
    Node: a ? a : b
  6. Nonterminal ? is read, triggering the right-associativity rule. Associativity decides:
    node: a ? a : (b ?
  7. Term c is read.
    Node: a ? a : (b ? c
  8. Nonterminal ? is read, re-applying the right-associativity rule.
    Node: a ? a : (b ? (c ?
  9. Term c(b) is read.
    Node: a ? a : (b ? (c ? c(b)
  10. Nonterminal : is read.
    Node: a ? a : (b ? (c ? c(b) :
  11. Term b is read.
    Node: a ? a : (b ? (c ? c(b) : b
  12. Nonterminal : is read. The ternary operator ?: from previous scope is satisfied and the scope is closed.
    Node: a ? a : (b ? (c ? c(b) : b) :
  13. Term null is read.
    Node: a ? a : (b ? (c ? c(b) : b) : null
  14. No tokens to read. Close remaining open parenthesis.
    #Result is: a ? a : (b ? (c ? c(b) : b) : null)

Better readability

The ugly oneliner from above could (and should) be rewritten for readability as:
(Note that the indentation does not implicitly define correct closures as brackets () do.)

a
  ? a
  : b
      ? c
        ? c(b)
        : b
      : null

for example

return a + some_lengthy_variable_name > another_variable
        ? "yep"
        : "nop"

More reading

Mozilla: JavaScript Conditional Operator
Wiki: Operator Associativity


Bonus: Logical operators

var a = 0 // 1
var b = 20
var c = null // x=> {console.log('b is', x); return true} // return true here!

a
  && a
  || b
      && c
        && c(b) // if this returns false, || b is processed
        || b
      || null

Using logical operators as in this example is ugly and wrong, but this is where they shine...

"Null coalescence"

This approach comes with subtle limitations as explained in the link below. For proper solution, see Nullish coalescing in Bonus2.

function f(mayBeNullOrFalsy) {
  var cantBeNull = mayBeNullOrFalsy || 42                    // "default" value
  var alsoCantBe = mayBeNullOrFalsy ? mayBeNullOrFalsy : 42  // ugly...
  ..
}

Short-circuit evaluation

false && (anything) // is short-circuit evaluated to false.
true || (anything)  // is short-circuit evaluated to true.

Logical operators
Null coalescence
Short-circuit evaluation


Bonus2: new in JS

Proper "Nullish coalescing"

developer.mozilla.org~Nullish_coalescing_operator

function f(mayBeNullOrUndefined, another) {
  var cantBeNullOrUndefined = mayBeNullOrUndefined ?? 42
  another ??= 37 // nullish coalescing self-assignment
  another = another ?? 37 // same effect
  ..
}

Optional chaining

Stage 4 finished proposal https://github.com/tc39/proposal-optional-chaining https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining

// before
var street = user.address && user.address.street
// after
var street = user.address?.street

// combined with Nullish coalescing
// before
var street = user.address
  ? user.address.street
  : "N/A"

// after
var street = user.address?.street ?? "N/A"

// arrays
obj.someArray?.[index]

// functions
obj.someMethod?.(args)

1 Comment

you're detail is siiiiick!
17

In simple words:

var x = (day == "yes") ? "Good Day!" : (day == "no") ? "Good Night!" : "";

Comments

7

if-else:

a = b ? (true block) : (false block)

if-else if-else:

a = b ? (true block) : b = c ? (true block) : (false block)

if:

a = b && (true block)

if-else-if(nested):

a = b ? (true block) : b = c && (true block)
  • note think so much, just implement and see the results, where a, b and c is variable

1 Comment

simple is better
5

This is use mostly for assigning variable, and it uses binomial conditioning eg.

var time = Date().getHours(); // or something

var clockTime = time > 12 ? 'PM' : 'AM' ;

There is no ElseIf, for the sake of development don't use chaining, you can use switch which is much faster if you have multiple conditioning in .js

Comments

5

I know this is an old thread, but thought I'd put my two cents in. Ternary operators are able to be nested in the following fashion:

var variable = conditionA ? valueA : (conditionB ? valueB: (conditionC ? valueC : valueD));

Example:

var answer = value === 'foo' ? 1 :
    (value === 'bar' ? 2 : 
        (value === 'foobar' ? 3 : 0));

Comments

3

You can chain as much conditions as you want. If you do:

var x = (false)?("1true"):((true)?"2true":"2false");

You will get x="2true"

So it could be expressed as:

var variable = (condition) ? (true block) : ((condition)?(true block):(false block))

Comments

3
  a === "a" ? do something
: a === "b" ? do something
: do something

1 Comment

Hi, welcome to stack overflow. For a useful answer this reaction needs to be extended. Explain why this is an answer to the question.
1

if i use code like this

const alpha = a ? a : b ? b : c

it will get

Extract this nested ternary operation into an independent statement.

from so i recommend to use this

const alpha = a || b || c

it works for me

Comments

1

This has worked much better for my use case when I was writing automation for n8n :)

You could accomplish this by wrapping your switch statement in an IIFE.

(()=>{
  switch (key) {
    case 'foo' : return 4;
    default : return 1;
  }
})();

Comments

0
var x = 10;

if (x === 0) {
    console.log("Neither positive nor negative!");
} else if (x > 0) {
    if (x < 10) {
        console.log("Single-digit positive number!");
    } else {
        console.log("More than one-digit positive number!");
    }
} else {
    console.log("Negative number!");
}

Ternary operator with nested loops , indented version

(x === 0) (if)
    ?console.log("Neither positive nor negative!")
:x>0 (else if)
    ?(x< 10) (if)
        ?console.log("Single-digit positive number!")   
        :console.log("More than one-digit positive number!") (else)
:console.log("Negative number!") (else)

It's hard to read , and it takes some learning curve to translate from your brain , especially for nested loops

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.