How to understand Ternary JavaScript expression?

Viewed 52

I'm bad with JS at now, especially with the operator "?"

And I'm trying to understand the following code.

Maybe it could be more friendly ?

So, if I don't want to use this operator, how can it be looks.

JavaScript code:

function(t) {
       for (var e, r = t.length, n = "", i = 0, s = 0, a = 0; i < r; )
           (s = t.charCodeAt(i)) < 128 ? (n += String.fromCharCode(s),
           i++) : s > 191 && s < 224 ? (a = t.charCodeAt(i + 1),
           n += String.fromCharCode((31 & s) << 6 | 63 & a),
           i += 2) : (a = t.charCodeAt(i + 1),

           e = t.charCodeAt(i + 2),
           n += String.fromCharCode((15 & s) << 12 | (63 & a) << 6 | 63 & e),
           i += 3);
       return n
   }
2 Answers

It seems like this is same as:

function(t) {
       for (var e, r = t.length, n = "", i = 0, s = 0, a = 0; i < r; )
           if((s = t.charCodeAt(i)) < 128) {
              n += String.fromCharCode(s);
              i++;
           } else if(s > 191 && s < 224) { 
              a = t.charCodeAt(i + 1);
              n += String.fromCharCode((31 & s) << 6 | 63 & a);
              i += 2;
           } else {
              a = t.charCodeAt(i + 1);
              e = t.charCodeAt(i + 2);
              n += String.fromCharCode((15 & s) << 12 | (63 & a) << 6 | 
              63 & e);
              i += 3;
           }
       return n
   }

This is an overly complicated expression involving multiple ternary operators.

I think it should be simplified.

A ternary operator behaves like an if but it is an expression that returns one value out of 2 options, depending on the first operand.

For example:

operand ? valueIfTrue : valueIfFalse is a ternary expression that returns valueIfTrue if operand is "truthy" and returns valueIfFalse if operand is "falsey".

You can substitute any expression in place of valueIfTrue and valueIfFalse and this way you can get really complicated expressions, sometimes unnecessarily complex.


As an example of making expressions complicated, let's consider: For example: operand ? valueIfTrue : valueIfFalse

If we then replace valueIfTrue with another ternary operator, e.g. myOtherOperand ? myOtherIfTrue : myOtherIfFalse then the original expression becomes:

operand ? myOtherOperand ? myOtherIfTrue : myOtherIfFalse: valueIfFalse

This is not a nice way to write it, it can be improved like this, I just put parenthesis.

operand ? (myOtherOperand ? myOtherIfTrue : myOtherIfFalse) : valueIfFalse

It can be improved again by formatting like this:

operand 
    ? myOtherOperand
         ? myOtherIfTrue // if both operand and myOtherOperand are true
         : myOtherIfFalse // if operand is true and myOtherOperand is false
    : valueIfFalse // this will be returned if operand is false

This shows that code formatting is essential for understanding it. But of course the first step is to have simple code. Anyways, here is how I would format the code in the question so it can be easier to understand:

function myFunction(t) {
    for (var e, r = t.length, n = "", i = 0, s = 0, a = 0; i < r; ) {
        (s = t.charCodeAt(i)) < 128
            ? (n += String.fromCharCode(s), i++)
            : s > 191 && s < 224
                ? (a = t.charCodeAt(i + 1), n += String.fromCharCode((31 & s) << 6 | 63 & a), i += 2)
                : (a = t.charCodeAt(i + 1),
                   e = t.charCodeAt(i + 2),
                   n += String.fromCharCode((15 & s) << 12 | (63 & a) << 6 | 63 & e),
                   i += 3); // end of ternary operators
        return n;
    }
}

Now it is clearer and we see statements separated by commas inside of the two ternary operators that are used. Commas are used to execute multiple things in the same expression, e.g. (n += String.fromCharCode(s), i++) will increase n and also i. In this case, it is better to move those outside of a ternary and into a normal if statement like this:

function myFunction(t) {
    for (var e, r = t.length, n = "", i = 0, s = 0, a = 0; i < r;) {
        const firstCheck = (s = t.charCodeAt(i)) < 128;
        const secondCheck = s > 191 && s < 224;
        if (firstCheck) {
            n += String.fromCharCode(s);
            i++;
        } else if (secondCheck) {
            // This is originally: (a = t.charCodeAt(i + 1), n += String.fromCharCode((31 & s) << 6 | 63 & a), i += 2);
            a = t.charCodeAt(i + 1);
            n += String.fromCharCode((31 & s) << 6 | 63 & a);
            i += 2;
        } else {
            // this is originally:
            // (a = t.charCodeAt(i + 1),
            //       e = t.charCodeAt(i + 2),
            //       n += String.fromCharCode((15 & s) << 12 | (63 & a) << 6 | 63 & e),
            //       i += 3);

            a = t.charCodeAt(i + 1);
            e = t.charCodeAt(i + 2);
            n += String.fromCharCode((15 & s) << 12 | (63 & a) << 6 | 63 & e);
            i += 3;
        }

        return n;
    }
}

So basically break it down and take it step by step to understand it, then you can change it because you understand it.

Related