JavaScript gotchas - not all your conditions are booleans

aloisseckar

Alois Sečkár

Posted on November 20, 2023

JavaScript gotchas - not all your conditions are booleans

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)
Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

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!

💖 💪 🙅 🚩
aloisseckar
Alois Sečkár

Posted on November 20, 2023

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related