Why JavaScript's == Doesn't Always Behave as You Expect
Let's say we have a number, 20
, and a string, "20"
. We compare them loosely using ==
:
const numVal = 20; const stringVal = "20"; console.log(numVal == stringVal);
What do you expect? Should it be true
or false
?
It turns out to be true
.
Now, let's look at another example. We have a boolean, true
, and a string, "true"
. Again, we compare them loosely:
const boolVal = true; const stringVal = "true"; console.log(boolVal == stringVal);
What do you expect to see? true
or false
? It logs false
.
So why does it behave differently in the first example compared to the second?
Let me walk you through how JavaScript's loose equality (==
) really works.
When we use ==
to loosely compare values in JavaScript, if the types are different, both values are coerced to the same type and then compared to see if they have the same value.
The general rule of JavaScript's coercion is simple: "If the types aren't the same, try to compare them as numbers." Let's look at some examples to see how this works.
Comparing a String to a Number
When you compare a string to a number, JavaScript tries to convert the string into a number first:
const numVal = 10; const stringVal = "10"; console.log(numVal == stringVal); // true
Here, "10"
is converted to the number 10
, so the comparison evaluates to true
.
Comparing a Number to a Boolean
When you compare a number to a boolean, JavaScript converts the boolean to a number. In JavaScript, true
is 1
and false
is 0
, so the comparison results in true
:
const numVal = 1; const boolVal = true; console.log(numVal == boolVal); // true
Comparing a String to a Boolean
When comparing a string to a boolean, JavaScript first tries to convert both values to numbers:
const stringVal = "1"; const boolVal = true; console.log(stringVal == boolVal); // true
Here, "1"
is converted to the number 1
, and true
is also converted to 1
, so the comparison returns true
.
However, JavaScript is quite literal when converting values. It won’t try to interpret words like "twenty"
as numeric values:
const stringVal = "twenty"; const numVal = 20; console.log(stringVal == numVal); // false
In this case, "twenty"
is converted to NaN
, and NaN
is not equal to any number (not even itself). So, the comparison evaluates to false
:
console.log(NaN == 20); // false
Exceptions
There are a few exceptions to this rule. For example, null
and undefined
are only loosely equal to each other, but not to any other values:
console.log(null == undefined); // true console.log(null == 0); // false console.log(undefined == false); // false
Also, symbols behave like objects because they have reference identity:
const sym1 = Symbol("id"); const sym2 = Symbol("id"); console.log(sym1 == sym2); // false
Get my free, weekly JavaScript tutorials
Want to improve your JavaScript fluency?
Every week, I send a new full-length JavaScript article to thousands of developers. Learn about asynchronous programming, closures, and best practices — as well as general tips for software engineers.
Join today, and level up your JavaScript every Sunday!
Thank you, Taha, for your amazing newsletter. I’m really benefiting from the valuable insights and tips you share.