Pergunta

According to MDN Logical Operators page:

false && anything is short-circuit evaluated to false.

Given this information, I would expect false && true || true to evaluate to false. However, this is not the case. The expected result (false) is only given when the statement is written like:

false && (true || true)

A coworker and I have tried to work this out and the closest thing we could come up with is that the statement is being evaluated by order of precedence. According to the MDN Operator Precedence logical-and has a higher precidence over logical-or, suggesting that the condition is evaluated as if false && true were a single statement, which then moves on to determine the boolean condition of false || true which is then true. Written out, this would be:

(false && true) || true

Something is wrong here. It's either the documentation, the JavaScript parsing logic, or my interpretation.

Edit:

I've added a bounty because none of the answers given truly understand the question. As stated above: the MDN Logical Operators page states exactly: "false && anything is short-circuit evaluated to false."

"anything" means "anything"!

Foi útil?

Solução

Your confusion all comes down to a misunderstanding of precedence.

A mathematical analogue would be "Zero multiplied by anything equals zero." Consider the following expression:

0 x 100 + 5

In any programming language, or a decent calculator, this evaluates to 5. The "zero times anything" axiom is true - but the "anything" in this case is 100, NOT 100 + 5! To see why, compare it to this:

5 + 0 x 100

It doesn't matter whether you add the 5 at the beginning or the end - the operator precedence rules remove ambiguity from the statement.

In JavaScript boolean logic, && has higher precedence than ||. Since each operator is commutative, writing

false && true || true

is exactly the same as writing

true || false && true

Outras dicas

The language works by parsing an expression into abstract syntax tree. Your expression false && true || true gets parsed into this:

          ||
         /  \
       &&    true
      /  \
 false    true

Only after building the AST, the short-circuited evaluation can take place. The

false && anything is short-circuit evaluated to false.

quote applies only to a valid sub-tree where false and anything are subtrees of && node, like this:

       &&
      /  \
 false    true

which means only the false && true gets short-ciruit evaluated to false and resulting false || true is evaluated to true

You are looking at precedence wrong.

&& is done first, then || so what it looks like is how you wrote it:

(false && true) || true

So the MDN link is correct.

JavaScript will parse this expression this way:

1) false && true //evaluates to false
2) false || true //equals true. The first false is the result above

It's easy to trace how JavaScript parse this whole expression this way:

(function(){alert(1); return false; })() && 
(function(){alert(2); return true; })() || 
(function(){alert(3); return true; })()

Let's put it this way. Somebody who wrote this MDN article phrased it quite badly/did small mistake

As you pointed out it says:

false && anything is short-circuit evaluated to false.

And any reasonable person would assume that anything is logical expression of any complexity. However, this would be wrong reading (contradicting to boolean logic rules).

false && true || true == true

Two other answerers explained already why it's so. It's just an order of logical operators && and ||. First && is handled, next || is handled

Now, getting back to bad phrasing. What they should have said is following. Please notice additional parenthesis which I added.

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

I am using here parenthesis as a way to show that the rest of logical expression should have been evaluated independently of "false" part. If it's evaluated independently then short-circuiting it works fine because false && == false.

However, as soon as we have some expression which can't be evaluated independently then original phrasing doesn't work.

As example false && true || true can't be evaluated independently, because of order or logical operations. However false && doSomething() can.

Consider this elementary arithmetic expression first:

A * B + C

Multiplication takes precedence, so the result is

(A * B) + C

Similarly, && takes precedence, so

A && B || C

Is the same as:

(A && B) || C

As far as short-circuiting goes, the Anything that might be shortcutted is B if A is false. So if you had something like:

(false && takesALongTimeToDetermine()) || true

It would skip evaluating takesALongTimeToDetermine()

I should note this: short-circuiting will never ever change the answer. It is an optimization that is made. Since && can only evaluate to true if both operands are true, it won't bother checking what the second operand is if the first is false because it already knows the answer is false. A reciprocal optimization is done with ||: if the first operand is true, it'll return true without considering the value of the second operand. This optimization exists so that your code will run faster - it will never change the answer. The only reason it's mentioned in MDN at all is because if your && has one operand that will take a lot longer to calculate than the other, you aught to list it second. (It's also important because if takesALongTimeToDetermine() does something besides just return a value, IE, if it prints a log statement that you're expecting, you won't see it if the function is short-circuited. But this still has nothing to do with the answer returned by &&.)

You're right that the phrasing on MDN Logical Operators is a bit ambiguous.

You should not think of anything as anything that comes after an &&, but as any right hand side operator to &&.

&& expects 2 expressions: one on the left hand side of && and one on the right hand side.

In your example: false && true || true, the false is the left expression and the first true is the right expression. The following || true is not part of the what the && operator will evaluate.

The short-circuit is meant to not waste cycles evaluating the right expression, if it can no longer effect the result of the logical operator.

In this example, it means that the right hand side expression (true) of false && true will be ignored (since || true is not part of that expression)

So in execution, this is what will happen:

  • Logical operator && will be evaluated first
  • It has 2 expressions, on both sides of the &&, which need to be evaluated
  • First expression (false) evaluates to false
  • Second expression (true) is short-circuited, because no matter the result, the logical operator can never result in anything but false
  • false && true has been evaluated to false
  • Logical operator || will be evaluated next (the result of false && true was false, so that makes for false || true)
  • First expression (false) evaluates to false
  • Second expression (true) evaluates to true
  • false || true has been evaluated to true.
  • End result: true

What you are probably missing that operators only take a single argument on each side of the operator into account.

So from: false && true || true Only the first true is taken into account when comparing to the false .

So this evaluates to false || true and that finally evaluates to true

The 'anything' part of the MDN article, might be a bit misleading in your case.

The reason why this evaluates to true is because OR has higher precedence than AND, so it's equivalent statement would be:

(false && true) || true

Which is a tautology since false || true will always evaluate to true.

False boolean = 0;

True boolean = 1;

"&&" operator = multiplication operation;

"||" = addition;

ok? So, if you've this:

if(true && false || true)

is equal to this:

((1 x 0) + 1)

Your interpretation is incorrect, and you're correct that the operator precedence is why it evaluates to true. What you're missing is the meaning of anything in the context of an abstract syntax tree.

Because of the order of operations, you end up with a tree like

          ||
      /        \
     &&        true
   /    \
false   anything

The scope of anything, doesn't include the true on the right hand side of the tree.

You can see some notes from Ohio State on ASTs here. They're applicable to every language.

The "false" and "anything" in "false && anything" are absolutely referring to Javascript expressions/values (as diagrammed in @Erbureth's answer) , not to your source code. Here are examples to prove this statement:

Javascript code that "short circuits" (one on each line)

var a=false; a && 3
!1 && alert("Never!")
(1==2) && "x"

Javascript code that does not "short circuit" (one on each line)

<script>false && </script><p>Other page content...</p></body></html>
false && * x^.++@; true
"false && true"

Hopefully these inane examples help to clarify why it is meaningless to apply the rule you are citing to source code. The rule meant to be applied to the value/subtrees that result after parsing the source code (at which time order of operations have been applied)

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top