The goal: hide the number of correct answers if the student hasn’t answered any questions yet.
Why doesn’t &&
work as expected here?
Code with error
Corrected code
Explanation
&&
(the logical AND operator) can be a convenient shortcut in JavaScript. But what exactly is the difference between the two code snippets above? To answer that, it helps to know what &&
does.
Logical AND in C
Allow me to wax nostalgic for a moment. I first encountered &&
in C , where the operator’s sole purpose is to logically combine multiple expressions.
Take the expression a && b
. I’ll call a
and b
“sub-expressions” here. To get the value of a && b
, you need to look at each sub-expression individually. If both a
and b
are true, then a && b
evaluates to true; otherwise a && b
evaluates to false. As a kind of shorthand, I mentally read the statement a && b
as “a
and b
are (both) true.”
A couple examples:
An interesting side-effect of this: if the first sub-expression evaluates to false, C won’t even look at the second sub-expression. All of the sub-expressions need to be true in order for the expression with &&
to return true — so if the first sub-expression is false, then the whole expression evaluates to false. No need to process the rest of the expression.
Surprisingly, this code runs without error:
Since 90 < 20
is false, C can set never_divide_by_zero
to false without evaluating the second expression (6/0 < 20
). The illegal division by zero never occurs!
Logical AND in JavaScript
JavaScript takes this one step further by returning one of the expressions instead of a boolean. Like C, JavaScript evaluates the expressions separated by the &&
operator from left to right. Also like C, JavaScript will stop at the first falsy expression, since no more evaluation is needed to know the whole thing is false.
However, instead of returning false
at that point, JavaScript returns the value of the first falsy expression. (If none of the expressions turns out to be falsy, JavaScript will return the last expression.) Consider this function:
getErrorString
returns the first falsy value it finds in the logical AND of the two sub-expressions in the return
statement. Say getErrorString
was passed the empty string (""
) as the argument. In this case, errorString
would evaluate to falsy and be returned.
If errorString
is truthy , though, then the function will return the second sub-expression: the errorString
prefixed with a less-than-calm introduction.
Logical AND in JSX
This brings us back to the original code snippet with the error. It’s pretty common to see elements conditionally displayed in JSX using the &&
operator:
If someExpression
is truthy, then the above will evaluate to the <div>
(that is, the last truthy expression in the logical AND statement). However, if someExpression
is falsy, then the statement will stop evaluation and return someExpression
, equivalent to this:
This works as expected if someExpression
results in empty JSX. For example, if someExpression
is null
, JSX won’t create an element from that. Same with values of undefined
or false
for someExpression
.
However, some falsy expressions do get converted into JSX elements. Recall the original Code Check snippet:
Suppose numAnswered
is 0
. The value 0
is falsy, so numAnswered
is returned without considering the “Total correct” element. So far so good… except that 0
is perfectly legitimate JSX. So the above expression becomes 0
as far as JSX is concerned, and JSX happily displays the 0
on the page. (Full disclosure: I have not asked JSX, so I’m not entirely sure how it feels about displaying 0
on the page.)
To get make sure your code doesn’t fall into this trap, it’s a good idea to use a boolean sub-expression before the &&
(something you know will evaluate to true
or false
). In the corrected snippet above, I used numAnswered > 0
. You could also use a ternary to avoid the “0
is both falsy and legitimate JSX” issue.
The moral of the story
The next time you see a stray 0
on a web page (I see them from time to time!), it’s a pretty good guess that someone misapplied the &&
operator.
Further reading
- Check out the React docs on using the
&&
operator for conditional rendering . - MDN talks about
&&
’s counterpart:||
(logical OR)