There is a piece of JavaScript syntax I, and others, seem to always want to work and it doesn't.
const isThisOrThat = "that" === ("this" || "that")
// this is false
Why doesn't this work? Let's talk about it!
Inside the parens
If we go by order of operations, the inside expression evaluates first.
What does "this" || "that"
mean in JavaScript?
I'll be honest, this one breaks my math brain a bit. In math, a || b = b || a
. The or operator is commutative, so order doesn't matter. That's not true in JavaScript, order matters a lot.
Let's look at two examples.
const example = "" || "that"
// "that"
The first thing JavaScript does is check for the "existence" of the first value. JavaScript is checking for a falsey value, empty string is falsey. Since the first value doesn't exist, it returns the second value.
This happens even if the second value is also falsey.
const example = "" || ""
// ""
So what happens if the first value is truthy, as in our original example?
const example = "this" || "that"
// "this"
example
evaluates to "this"
.
Equality check
Now we start to realize why our expression up top doesn't work. We can break it into two pieces.
const example = "this" || "that"
const isThisOrThat = "that" === example
// false
At the time that we're checking equality, the string "that"
is nowhere to be found.
What makes this strange is that order matters.
const example = "that" || "this"
const isThisOrThat = "that" === example
// true
Flipping the original or expression changes the resulting equality check.
Making sure this works
If we truly want to check both strings, we need to check equality twice.
const isThisOrThat = "that" === "this" || "that" === "that"
// true
Alternatively, we can use an array check. This one feels a bit more natural.
const isThisOrThat = ["that", "this"].includes("that")
// true
Or is weird
People use or a lot to flip values or set defaults, etc. It's never been my favorite because of examples like the ones above. Once you start composing that expression it can confuse the issue.
Top comments (10)
Yeah, at first it can be confusing. Just one more point to add - In case of
Logical OR
||
it behaves as a short circuit. So if you use expressions and your first expression becomes truthy, other expressions will never be evaluated. If there is a function call, it will not execute.Absolutely
I agree that this is a very confusing point that result in really bad code. TypeScript is in a quest to fix issues such as this. I don't think JavaScript || breaks any math logic. It is still commutative. Problem is that we sees "this" and "that" as two string, but for the || operator, they are both just two boolean 'true's. Your equation, a || b = b || a, turns in to true || true = true || true when both a and b is a string. When evaluating this logic with || operator, it doesn't matter which true value sends to the user so to be fast JS (or any other sane language) returns the first result. To avoid confusion, you could always use !! to get the boolean value before do the ||. i.e !!a || !!b
Ah, but it doesn't return a boolean. It returns the value. So yes, the operation logic is reasonable, but the return structure breaks the concept. It's no longer commutative at that point.
Yeah, stuff like this can be counter-intuitive. The nice thing is that once you learn this in a language like JavaScript, you now understand it in a number of other languages as well.
Thanks for the write-up!
There are two finer points of the language that may be confusing sometimes even to experienced developers.
The first one is type coercion, which is an automatism to align values for the task at hand. For example, a logical operator will coerce any value to a boolean for the sake of evaluation. An empty string is falsy, a string containing characters isn't. There's quite a complex set of rules to this, and it makes the language easily confusing.
That brings us to the second one, which is operator precedence. I'll spare you the details, it's just that some operators are processed prior to other ones.
Especially in combination, these two points lend themselves to a many WTF-moments when writing JavaScript.
No question. And thatβs the former is what most of this post focuses on. It resolves each side of the operator to a Boolean and operates accordingly.
As someone who learnt coding through school (5 years at a higher technical school) this is something I don't even consider confusing because of how conditionals were taught to me, it never really was something I was facing because we started out with Java and C# and such logic wouldn't have worked. So when I started coding in Javascript alot of stuff that I see people learning it by themselves are struggling with were already clear for me.
Appreciate the effort though, very interesting write up! Keep it up!
Great js quirk analysis Laurie.
Thanks to eslint, this would never get checked in.
As Yoda would say....
Confuzzled, I made you;
Amuse me, this does.
:)
Nice post.