One thing I like about JavaScript is its shothand evaluation whether a variable contains a value. Instead of the tedious if (text !== undefined && text !== null && text.length > 0)
comparison we can just write if (text)
and it works the same.
You just need to be careful if you want to use more such conditions. When you type:
let text1 = 'text1'
let text2 = 'text2'
console.log(text1 && text2)
console.log(text1 || text2)
you won't get true
, as inattentive JS devs tend to expect from time to time, but 'text2'
from the first and 'text1'
from the second log. Huh? 😵
The truthiness of variable text1
is still being evaluated first. Therefore, the program advances to text2
, but after the evaluation is finished, JavaScript is left with the real value of the string, and so it returns it. The unsuspicious machine doesn't expect you didn't feed it boolean
values as you properly should. In the later case with "or", text1
is truthy, so it satisfies the condition and the actual value of the variable is dropped from the expression. The simple if (text)
in fact does exactly the same. But since we don't work with the returned value any futher as we just wanted to know if something is there, we don't even notice and it works for us. But not anymore with two or more variables.
Similar shenanigans are probably the reason why many programmers gained feeling that JavaScript is all but an evil and mess that should be avoided at all costs. While it is rather their fault when they try to cram illogical combinations into it. “Play stupid games, win stupid prizes.”.
I originally thought I'd go in deeper deatail about the rules for evaluating operators in JavaScript, but it's actually a bit complicated with all the edge cases, so here's just a link to the documentation for &&
and ||
for those who are interested (there are also other logical operators).
In order to make logical operations work really logically, we need to feed them operands that are actual boolean
, i.e. true
or false
by themselves, and not thanks to some background magic. Otherwise, sooner or later you will find yourself debugging the application in disbelief and wondering why the condition isn't evaluated as you expected.
If you're worried that this means going back to a "chatty" explicit comparison with several possible (non)values, do not despair. We have a trick for that. Simply rewrite it as:
console.log(!!text1 && !!text2)
console.log(!!text1 || !!text2)
It works! But why? 👀
Don't worry, I had a "WTF?" moment when I first saw this too. But there is nothing magical about double negation. Again, the JavaScript starts by evaluating the truthiness of the text1
variable, and since 'text1
' is there, it has the value of true
internally. Now we negate it with the first !
and then we negate with the second !
again. Maybe you remember from mathematics - "The product of two negatives is a positive".
If it were the other way around and text1
was undefined
, null
or an empty string, JavaScript would first say false
, the first negation would make true
and the second would finally return false
.
Using the concatenation of two logical NOTs !!
, we get a simple, universal and always functional conversion of JavaScript values into boolean
expressions, which can then be safely used and chained for logical evaluation of conditions. Keep this in mind when writing your JS code and be prepared to look for incorrect usages if you seek for bugs in existing programs.
Have you ever encountered this in your code or codes you had to debug? Share your experience in the comments!
Top comments (2)
I love this feature of JavaScript, but there are some gotchas developers should be aware of:
1) Empty arrays are truthy, one would easily have thought otherwise
2)
NaN
is falsy. Instead of trying to check if a number isNaN
, check if a number is falsy. this could be very handy in certain circumstances, except for that3) The number
0
is falsy. Yep thats right, so if you use anif (number) { ...}
to safeguard againstNaN
, you won't perform any computations on 0 as well.In JSX, there is also an issue with conditions not being boolean, say in usages like this:
If, somehow,
someVariable
is NaN here, the letters "NaN" would show up on the screen! I'm surpriced how often I've actually spotted "bugs" like this in applications I have maintained. Often they have gone unnoticed because it's been barely visible, or just been a temporary state. In cases like these, you can use!!
to enforcesomeVariable
to become a boolean as well, and React won't render booleans to the screen:Thank you for pointing out those exceptions. I got caught by
0
being falsy couple of times as well.And btw my personal favorite among falsy JS values is
document.all
, although one probably won't use it so often in the actual code.