I always assumed that operators like &&
and ||
are for comparing true
and false
statements on both sides.
But I'm seeing a pattern in React where, on the right side is a function and the left is a truthy statement that will then allow the right to be executed.
Example:
truthy statement && function
I understand that JavaScript will check this from left to right, so left being true will then allow it to check the right. But my assumption is the right should expect a true
or false
statement, but in this case it's just a function.
I'm so used to seeing the &&
operator in this context:
if (true && true) {
// Execute this
}
That this:
true && execute this
Works at all.
I guess my assumption is that JavaScript will just evaluate anything next to an operator whether it returns a true
or false
.
Top comments (4)
Being an operator it's part of an expression:
"An expression is any valid unit of code that resolves to a value."
Logical AND and Logical OR are binary operators, i.e. they require two operands. Those operands can be expressions because an expression resolves to a value. A function invocation is considered an expression because it will resolve to a value after the call (even if it is just
undefined
).On top of this
&&
and||
use short circuit evaluation:lhs && rhs
therhs
expression will never be evaluated iflhs
evaluates to a falsy value. That falsy value is what the&&
operator evaluates to.lhs || rhs
therhs
expression will never be evaluated iflhs
evaluates to a truthy value. That truthy value is what the||
operator evaluates to.So
somethingFalsy && fn(value)
won't executefn(value)
whilesomethingTruthy && fn(value)
will executefn(value)
. In the former casesomethingFalsy
will be the resulting value (ignored if not used) while whateverfn(value)
returns is the result for the latter.If you're out shopping for something to nibble on, and you have $1 left in your pocket, and you put something in your basket that costs $1, does it make sense to keep adding more things?
Why not?
Because you know that you've already reached the limit, and adding more isn't going to work.
That's how expressions work:
When this code is run by the Javascript engine, it'll get to each part of the expression in turn, left-to-right, and test it. We know
n > 5
is correct, andtrue
, and we also known > 6
istrue
. However, when we reachn > 11
we can throw out the whole thing because the expression as a whole can no longer betrue
. It doesn't matter what parts of the expression come afterwards, it can never be true.The parser does this as it goes, basically to save effort. It can run your code faster if it doesn't have to do a lot of working-things-out that it knows are pointless. You might think that testing
n > 20
is going to take so little time that it doesn't make any difference, and you'd be right... but remember, expressions can include all sorts of things:And in this case, you don't want your supercomputer to use 1.21 gigawatts working out the weather forecast in ludicrous detail when you know it's not needed because you don't have sufficient
n
s to use it anyway.The second thing you need to know is that this:
is as valid a thing as this:
i.e. you can have bare expressions in code and they're perfectly fine. They don't necessarily do anything, but they're not invalid.
So to put it together:
will work out the expression, just as if it was inside an
if
, from left to right, until it's sure it'strue
or certain it'sfalse
, and it'll do as little work as it can to find that out. The parser doesn't care that theconsole.log
here isn't returning anything useful for the expression, it doesn't know any different. It's processing it exactly as it processed then > 20
part.You don't often see this in Javascript. I'd go so far as to say it's not good style.
To borrow from Python, explicit is better than implicit, sparse is better than dense, and readability counts. Any of these could be written as a clear
if
which would be a lot easier to extend in the future.While it is true that short-circuit evaluation serves to avoid evaluating expressions unnecessarily, treating them as boolean operators hides an important fact: They aren't commutative.
With a purely boolean
AND
operator, you could start evaluating either side of the expression and stop if it was false.However, in JavaScript, this isn't the case, as even when the RHS evaluates to false, the LHS is still relevant, because it could be any of several falsey values, or a truthy value, in which case the operation would evaluate to its RHS.
This becomes more apparent when you rewrite an expression like this:
With many truly commutative operations, it is up to the language to define a clear order of evaluation.
For example, what would you expect
let foo = 1 ; String(foo++)+String(foo++)
to evaluate to? Normally one would expect12
, but depending on the language, such things may be clearly defined, or up to the implementation.In C++, for example, the order is unspecified, so such an expression could return both
"12"
or"21"
, depending on what order the compiler decides to do things in.Strictly specifying left to right evaluation, in this case, is a language feature, not an optimisation (and may, at times, actually hinder optimisation)
This totally looks like it could be by design of JavaScript.
262.ecma-international.org/12.0/#s...
Where in that: