DEV Community

Quratulaiinn
Quratulaiinn

Posted on

Why You Should Never Use (==) in JavaScript

While this topic may appear basic and familiar but I think we've all been there, using == when === was the better choice, only to wonder why our code behaves strangely.

So no "ugh you didn't even know this silly, it was so simple" comments please and let's unravel the mysteries of JavaScript's equality operators together.

Loose Equality

The loose equality operator == is designed for type coercion (datatype conversion), allowing JavaScript to convert operands to a common type BEFORE comparison.

While this can be convenient, it can also lead to subtle bugs.

Example 1: String and Number

const a = 10;
const b = '10';
console.log(a == b) // Result: true
Enter fullscreen mode Exit fullscreen mode
  • Even though a is a number and b is a string, we get true. This is because the type of the variable a is converted to a string before making the comparison.

  • After the comparison, the value is checked in both the variables. If it's same, we will get true otherwise we will get false.

But that's not a problem, at least the values are same?

Haha, just wait for it..

Example 2: NaN Comparison

NaN == NaN;  // Result: false
Enter fullscreen mode Exit fullscreen mode
  • Due to the complexities of NaN, using == to compare NaN values will ALWAYS return false.

  • For NaN checks, use isNaN() or a strict comparison: ===.

Example 3: String and Boolean

const a = true;
const b = 'true';
console.log(a == b)
Enter fullscreen mode Exit fullscreen mode

If you thought the answer is true, unfortunately that's not correct.

Surprised huh?

  • If either operand is a Boolean, it will be converted to a number (true becomes 1 and false becomes 0).
    Now, you know why the answer was true, not false in the above example.

  • It is because the value of the variable a (true) gets converted to a number before the comparison. So after comparison, we're basically comparing 1 and 'true' hence we get false because the variables contain different values.

Pretty unexpected behavior, I TOLD YOU.

Hence many experienced developers favor strict equality operator === for its strictness, as it reduces ambiguity and encourages explicit type handling.

Strict Equality

The strict equality operator === is, well, very strict. It compares both value and type, making it more predictable and less prone to unexpected results.

Example 1: String and Number

"5" === 5; // Result: false
Enter fullscreen mode Exit fullscreen mode

Since the types are different, the comparison returns false.

Example 2: Boolean and Number

false === 0; // Result: false
Enter fullscreen mode Exit fullscreen mode

In this case, false and 0 have different types, so the comparison is false.

Conclusion

In JavaScript, clarity and predictability are vital. While loose equality operator can be convenient, it introduces potential pitfalls and surprises. The choice between == and === depends on your intent and having knowledge of both of the operators is must but there are reasons you should avoid using == in your code as we discussed above.

Hope it helps!

For more such content feel free to connect with me.

LinkedIn: https://www.linkedin.com/in/quratulain

GitHub: https://github.com/QuratAin

Top comments (33)

Collapse
 
jonrandy profile image
Jon Randy 🎖️ • Edited

Sorry, but this is poor advice. == is there for a reason, as is === - learn what they do and use whichever is appropriate on a case by case basis.

'Advice' that blanket bans parts of a programming language because they introduce 'surprises' is just a recipe for increasingly uninformed, lower skilled developers.

Unexpected code behaviour, or 'surprises' come when you do not fully understand your code, the code you are working on, or the language you are working with.

Collapse
 
joelbonetr profile image
JoelBonetR 🥇 • Edited

Extending on @jonrandy 's comment, the == operator is useful to avoid converting data and then check equality.

You don't always need something to be the same type to check if it has an equivalent value.

E.g.

data = await fetch(...)

if(data.id == 1) // doSomething
Enter fullscreen mode Exit fullscreen mode

You don't really care here if the response comes with the id property as number or if it got stringified and now it's a "1" or even if you got a float 1.0, nor you will obtain any benefit by doing:

data = await fetch(...)

if(Number.parseInt(data.id) === 1) // doSomething
Enter fullscreen mode Exit fullscreen mode

As a rule of thumb, use === whenever no conversions are expected to take place to avoid confusion.

E.g.

if (typeof x === "function") { 
  ...
}
Enter fullscreen mode Exit fullscreen mode

But feel free to use == whenever the inherent type casting is good.

Not using == won't solve bugs on it's own, having tests that cover all possible use-cases will, and AI nowadays helps a lot on that so it has even less sense to "ban" the usage of the loose equality IMHO.

Collapse
 
kiss_code profile image
kis.stupid

Yes, I use that for boolean checks & conversion at once -> isSomething == "true".
Simplifies code, converts string containing boolean value to an actual boolean, which can happen when e.g. the value was stringified to send as query string parameter.

Thread Thread
 
joelbonetr profile image
JoelBonetR 🥇 • Edited

Yes!
You can even shorten that in most cases and simply check

if (isSomething)
Enter fullscreen mode Exit fullscreen mode

Even though is not exactly an equivalent. Please note that the boolean conversion is a bit more tricky that what one may thought.
On the example above the runtime will check that isSomething is not null, nor undefined, that doesn't contain a zero as value and so on, whereas checking explicitly if something's equal to true or false is weird in JS, look:

undefined == true // false
undefined == false // false
null == true // false 
null == false // false
'a' == true // false
[1] == true // true
[2] == true // false
Enter fullscreen mode Exit fullscreen mode

you can directly write comparisons in the browser's console to test them out.

To solve that you can use the double negation that will cast to boolean, like so:

const checkTruthyness = (val) => !!val;
Enter fullscreen mode Exit fullscreen mode

or, if you prefer it

const checkTruthyness = (val) => Boolean(val);
Enter fullscreen mode Exit fullscreen mode

so you can

checkTruthyness(1) // true
checkTruthyness(3) // true
checkTruthyness('a') // true
checkTruthyness('') // false
checkTruthyness([]) // true
checkTruthyness(null) // false
checkTruthyness(undefined) // false
Enter fullscreen mode Exit fullscreen mode

or directly

if (!!isSomething)
Enter fullscreen mode Exit fullscreen mode

or

if (Boolean(isSomething))
Enter fullscreen mode Exit fullscreen mode

Hope you find better names than I did, tho 😂

Best regards

Thread Thread
 
kiss_code profile image
kis.stupid • Edited

I've been out of JS & TS for a while, I liked the double exclamation marks, is it still a thing?

What I meant to illustrate is that I found the '==' super useful.

true == "true" // true
true == "1" // true
Enter fullscreen mode Exit fullscreen mode

Or did I use it for everything that is not true?

false == "true" // false
"0" == "true" // false
undefined == "true" // false
null == "true" // false
"" == "true" // false
Enter fullscreen mode Exit fullscreen mode

I can't remember but leveraging all boolean operators can greatly improve your code readability, for example one-liner return statements instead of multi-line if statements.
Altho when it really matter, you might indeed be safer using the ===.

Thread Thread
 
joelbonetr profile image
JoelBonetR 🥇 • Edited

If you ask me, one just need to define what's valuable to compare at a given point in the program. Is it the value? value + type? any other thing?

Following the example I used above

if(data.view_id == 2) 
Enter fullscreen mode Exit fullscreen mode

if the backend changes and suddenly we get either "2" or 2 or "2.00" or [2] or ["2"] or... it is OK?

Sure, we just want to know which view is involved in this right? so why bother?

By using == if the backend changes and returns the same information (same value) wrapped in a different type or structure, the App won't break, we avoid a cut in the service and we don't need to fix and rebuild the App.

Now consider the following scenario:

if(data.view_id === 2) 
Enter fullscreen mode Exit fullscreen mode

now if the backend returns "2" instead of 2... Upsies, we need to fix it, rebuild and redeploy our App, users are not able to use it in the meantime, the company is probably loosing monies.

Of course one can rewrite it like so:

if(Number.parseInt(data.view_id) === 2) 
Enter fullscreen mode Exit fullscreen mode

but it looks cumbersome to me and I don't believe it brings any value to any developers involved nor to the app itself. We're explicitly instructing the program the same that == does by default.

If we stress it enough maybe the yoda style is more readable, idk at that point 😂

if(2 === Number.parseInt(data.view_id)) 
Enter fullscreen mode Exit fullscreen mode

jokes aside, In this use-case,

  • the == solution is more resilient and easy to read
  • the === one is less resilient and equally easy to read,
  • the parse + === one is equally resilient to the == one, but harder to read.

In other cases this may be completely different and that's why we have different tools 😅😂

Collapse
 
fjones profile image
FJones

While I agree in general, particularly the response example can be a trap. If you're used to using == there, you might well end up accidentally using it for == 0, where it does make an annoying difference.

Thread Thread
 
joelbonetr profile image
JoelBonetR 🥇 • Edited

Sure, now regarding the example I was thinking about, most databases are 1-indexed, meaning that the first element of their indexes is 1, including auto-increment initial values.
But again, it's a tool and it has sense in certain situations, the same way you'll probably use var when coding a videogame with JavaScript because you want (or even need) certain stuff to be in the global scope.

And yet again, having a test to check what happens when the value is == 0, if it makes sense in this specific function/method will hint you at possible undesired computation paths or errors before you release the code to production, plus consistent JSDoc will make others (and yourself in the future) aware of what it's supposed to do.

Best regards

Thread Thread
 
polaroidkidd profile image
Daniel Einars • Edited

It's an unnecessary tripping hazard. It's rather my code be expressive then depend on every Dev that reads it to understand the intricacies of === Vs ==

Thread Thread
 
joelbonetr profile image
JoelBonetR 🥇

fair enough 😂

Collapse
 
quratulaiinn profile image
Quratulaiinn

Makes sense.
Why You Should Never Use (==) in JavaScript --> Why You Should Avoid Using (==) in JavaScript.

Thread Thread
 
joelbonetr profile image
JoelBonetR 🥇 • Edited

--> When should you avoid using == in JavaScript 😁

Collapse
 
lopis profile image
Joao L.

Unexpected code behaviour, or 'surprises' come when you do not fully understand your code

If you're the only developer of your code, that's fine. But if you work on a long term project with changing teams with a variety of seniority levels, you can't assert that they know your code, or that you know theirs. If I see a == in my company's code, I can never know if that was on purpose or a mistake, but if we enforce use of ===, there's no more ambiguity.

I prefer clear code than clever code any day.

Collapse
 
merri profile image
Vesa Piittinen

== null or != null is hardly clever though. It is compact, it is common, it is useful, and pretty much anyone writing JS would be expected to eventually know it. It is a great conversation starter when someone encounters it the first time! You can teach people about the differences of undefined and null. Very valuable to have it in about any codebase.

Collapse
 
artxe2 profile image
Yeom suyun

I think this is at least a matter of taste.
In most cases, strict comparison is not required, and it is more common to use null == undefined.
If you know that other comparison operators convert to numbers and then compare them if the types are different, there will be no confusion.

Collapse
 
quratulaiinn profile image
Quratulaiinn

I agree, its important to have knowledge of how both work as i already mentioned in conclusion. But after you've understood something its more important to balance best practices with practical application.

Collapse
 
jonrandy profile image
Jon Randy 🎖️ • Edited

How will a junior dev ever gain a full understanding of how they both work and when it is appropriate to use each, if people insist on an irrational blanket ban on ==?

Best practice is to use the right tool for the job.

Thread Thread
 
quratulaiinn profile image
Quratulaiinn

The blog points out the 'why nots' not to stop learning, but to guide it. If we don't understand why something's bad, how can we get better anyway. No one's blocking the room for learning here.

Collapse
 
buchslava profile image
Vyacheslav Chub • Edited

Agree!

const a = 1;
const b = "1";
console.time("first");
for (let i = 0; i < 999999999; i++) {
  a === b;
}
console.timeEnd("first");

console.time("second");
for (let i = 0; i < 999999999; i++) {
  a == b;
}
console.timeEnd("second");
Enter fullscreen mode Exit fullscreen mode

The result:

first: 741.86ms
second: 6.926s
Enter fullscreen mode Exit fullscreen mode
Collapse
 
dsaga profile image
Dusan Petkovic

Its interesting to see the difference, definitely takes time for JS to do the coercion.

But in the real world it wouldn't really have any significant effect unless you're doing a million comparisons for some reason, in which case you're doing something wrong :D

Collapse
 
buchslava profile image
Vyacheslav Chub

Of course, my code is a bit artificial. And, of course, a well-formed real-life page contains less than a million comparisons. Even though it can have many comparisons, we sometimes can't imagine how many. Algorithms complexity estimation is always like an art ;) It could be sensitive. Anyway, it depends on functionality.

Thread Thread
 
dsaga profile image
Dusan Petkovic

Yea, good to know that it does make a difference

Collapse
 
quratulaiinn profile image
Quratulaiinn

Thank you for this addition.

Collapse
 
lopis profile image
Joao L.

While it's ok to use == sometimes, you're more likely to introduce bugs by relying on it, and will have a harder time debugging them too. Talking from experience. This is why I always enable the eslint rule eqeqeq in my projects that prevents me from accidentally, or purposely, using == instead of ===.

Collapse
 
miketalbot profile image
Mike Talbot ⭐ • Edited

There once was a dev who'd opine,
That linting was far from divine.
"It nags and it picks,
At my clever code tricks,
And refrains from a neat, clean design."

#abotwrotethis

Collapse
 
lopis profile image
Joao L.

Funny but I think the meaning is a bit lost in this one.

Thread Thread
 
miketalbot profile image
Mike Talbot ⭐

Hmmm, made sense to me. Though I guess it's pushing less common English to make the rhyme.

Thread Thread
 
lopis profile image
Joao L.

I felt like the opposite from "And refrains from a neat, clean design" was what I was hinting at

Collapse
 
joaomadeiraxyz profile image
João Victor

You should understand both and use both at the right time. For example, if I'm retrieving a value from a database and want to perform an action when the value is “true”, but I don't mind if the "true" value comes as a boolean or as a string, then I should use "==".

Collapse
 
joaomadeiraxyz profile image
João Victor

This could be used on a function that works with data from the code, and data from the database, if you are validating a value from the code it will likely be a boolean, but if you are getting the data from a database then depending on the way your database is configured it could be retrieved as a string

Collapse
 
quratulaiinn profile image
Quratulaiinn

Makes sense, its about keeping balance and knowing when to use which but when it comes to best practices i think === is a go to approach in most cases.

Collapse
 
dsaga profile image
Dusan Petkovic

I think both operators have its uses, but because it makes the code more clear in most cases you would want to use the strict equality operator.

It promotes more explicit code comparisons, and if some variable you're checking can return both undefined and null, 0, its more likely that the variable or data is not correct or not defined well.

Collapse
 
budokans profile image
Steve Webster • Edited

I wouldn't ban its use, but I'd discourage it.

When deciding on an equality operator, the question we should be asking ourselves is "Am I happy if type coercion potentially occurs before we perform this equality comparison?". If the answer is "no" - and almost always it will be - then use the strict equality operator. If the answer is "yes" and you understand the equality operator well, go ahead.

However, I suspect that often there may be clearer and more maintainable ways of approaching things than by using the equality operator. For example, if you're happy for -10 and 10 to be considered equal, how about using Math.abs()?

Math.abs(x) === Math.abs(y)

is clearer and more maintainable down the road than

x == y