· Jake Worth

JavaScript loose equality (==) and type coercion


Never use two equals (==); always use three equals (===): this is received wisdom in JavaScript. Is that the whole story? Let’s take a look.

In JavaScript, what do these evaluate to?

true == 1;
false == '';
0 == [0];
'1' == true;
null == undefined;
[] == false;

Answer: they are all true. Were any surprising to you? JavaScript uses the equal sign in three ways.

The first, =, is the assignment operator (const one = 1).

The second, ==, is the equality operator, AKA “twoquals.” It offers comparison via the “IsLooselyEqual” algorithm.

The third, ===, is the strict equality operator, AKA “threequals.” It offers comparison via the “IsStrictlyEqual” algorithm. === is the equality comparator most expect coming from other languages such as Go or Ruby.

The difference that distinguishes == is: if the operands are different types, the equality operator == attempts to convert them to the same type before comparing.

How that works is pretty complicated; you can find a description here: Equality Comparison and Sameness.

Let’s consider a concrete breakdown of one such comparison: why is [] == false true? Loose equality does not compare them as booleans. Roughly:

  1. false becomes 0 (ToNumber)
  2. [] becomes "" (ToPrimitive via toString)
  3. "" becomes 0 (ToNumber)
  4. 0 === 0 So [] == false is 0 == 0, which is true

So, should we ever use two equals? Here are two use cases. The first is comparing a value to null or undefined:

if (value == null) {
// Value is either null or undefined
}
if (value === null || value === undefined) {
// This is equivalent
}

The second is comparing identifiers that could be numbers or strings, such as those from an API1:

const id = element.dataset.userId; // string
if (id == 42) {
// true
}

I think the first example is more widely accepted. If you find implicit type coercion less readable than the alternative, as I do, I’d suggest avoiding them both.

Take it from Douglas Crockford, JavaScript ecosystem contributor:

“My advice is to never use the evil twins. Instead, always use === and !==.” —Douglas Crockford

Footnotes

  1. I wrote about a different way to approach this here: Accepting string or number IDs in TypeScript