Search code examples
javascriptoperator-keywordoperator-precedence

how the precedence of AND & OR is set when used together in javaScript


i am trying to understand the explanation for this code.

function Test() {
  var a = 0; var b = 0; var c = 0; var d = 0;

  if (a++ && b-- || c++) {
    console.log("if block")
  } else {
    console.log("else block")
  }
  console.log(b);
}

Test();

observation: when we execute this code the value of 'b' is 0; not '-1'. i think A && B is false but when it is again check || with c, it should be true. but when i run the code, else block executes. i am trying to find explanation for that. tried finding it out but didn't find anything helpful.


Solution

  • Let's take the if statement and break it down.

    a++ && b-- || c++
    

    The order of operating with ++ has two variants:

    1. a++ - returns the value of a, then increases by 1
    2. ++a - increases by 1, then returns the new value of a

    So the first part, a++ returns a, which when used as a boolean (since this is an if statement) will evaluate as false, and only afterwards it increases a by 1.

    An important thing to note now, is that JS has short-circuiting:

    If a part of the statement returns a "falsy" result and the rest of the statement relies on said result, the latter part of an expression will not be evaluated.

    Take this for instance:

    if (1 === 0 && console.log('test')) { 
      // ...
    }
    

    You will note that console.log never fires. That is because the && created an implicit condition, where the latter part doesn't need to be evaluated, as the condition preceding it was resolved as false.

    Now that we know this, we can see why the else fired, and why the rest of the expression didn't evaluate (thus, leaving b as 0).

    1. a++ - A is returned as 0, which is false in this context, and the if statement immediately fails, thus falling to the else statement.
    2. b-- and c++ were never evaluated, as it was short-circuited.
    3. Therefore, b and c remained 0. You can test that a is indeed 1, but the if statement was not aware of this quite yet.

    If you change your code a bit...

    if (++a && --b || ++c) {
    

    You will see that you do fall in the if statement log, and not the else.

    This is because:

    1. ++a will evaluate to 1, which is truthy
    2. --b will evaluate to -1, which is also truthy.
    3. Since the previous was truthy, there is no need to check the or that follows it, as the condition was already fullfilled.

    a will be 1, b will be -1, and c will remain 0.

    function Test() {
      let a = 0, b = 0, c = 0, d = 0;
    
      if (++a && --b || ++c) {
        console.log("if block")
      } else {
        console.log("else block")
      }
      console.log({ a, b, c });
    }
    
    Test();