== vs === in JavaScript

Reading Time: 4 minutes 🕑

Last updated: September 27, 2022.

Both == (the loose equality operator) and === (the strict equality operator) are used to test if two bits of data in JavaScript are the same or different.

If either operator judges two bits of data to be equal, the comparison will return the Boolean value true and otherwise false.

For most comparisons you make, both the loose and strictly equality operators return the same Boolean value:

/*** Basic comparisons using the loose and strict  equality operators ***/

2 == 2;   // Returns true
2 === 2;    // Returns true

2 == 4;    // Returns false
2 === 4,    // Returns false

"a" == "a";   // Returns true
"a" === "a";    // Returns true

If you are new to JavaScript, you may be tempted to use these interchangeably. But there is a significant difference.

Loose equality tests for equality of value only

The loose equality operator compares value only. It ignores data type. So a comparison between a numeric and string value, for example, can return true if the values are the same!

/*** Loose equality check ignores data type ***/

2 == "2"; // returns true

It achieves this by silently coercing both bits of data to the same type, so they can be compared. In the above example, 2 == "2" returns a predictable result.

But coercion can also lead to some unexpected results:

/*** Coercion can generate unexpected results ***/

console.log(0 == false);    // true
console.log("" == false);    // true
console.log(null == false);    // false
console.log(null == undefined);    // true

It is not easy to keep track of all the unexpected results generated by the loose equality operator coercion the two types under comparison.

Even if you are familiar with truthy and falsy values, this will not help you! In the example above, only falsy values are compared with each other. But the return values are mixed. Thus, you cannot rely upon your knowledge of truthy and falsy values to know what result the coercion will produce.

Strict equality test for equality of value and type

The strict equality operator is much more predictable, which can help to avoid unforeseen errors.

For example, if we make the same comparisons as we did with the loose equality operator, you can see a much more consistent behavior:

/*** Strict equality generates more predictable outcomes ***/

console.log(2 === "2"); // false
console.log(0 === false);    // false
console.log("" === false);    // false
console.log(null === false);    // false
console.log(null === undefined);    // false

The strict equality operator will only return true if the value and data type are the same. So, a comparison between a numeric and string value with never return true.

/*** Strict equality will only return true if there is equality of value AND type ***/

console.log(null === undefined);    // false
console.log(undefined === undefined);    // true
console.log(null === null );    // true

console.log(2 === "2");    // false
console.log("2" === "2");    // true
console.log(2 === 2);    // true

So which should you use?

There are in fact some differences of opinion.

But if you are new to JavaScript and want to adhere to best practices in your programming, there is a simple answer: always use the strict equality operator.

Why always use the strict equality operator?

The short answer: the strict equality operator is more predictable, helping you avoid unexpected outcomes and errors.

But taking advantage of the flexibility of the loose equality operator can be tempting.

Though we recommend always using the strict equality operator, there are two common exceptions to this rule that you will find in many existing code bases.

Let’s look at these now – and why, even in these cases, it is better practice to test for strictly equality.

Common exception #1: Testing for null or undefined

One way that you can take advantage of the flexibility of the loose equality operator is to test if a value is either null or undefined by placing either null or undefined on one side of the equality test. If the other value is either null or defined, true will be returned and false otherwise.

/*** null and undefined only return true against each other in loose equality ***/

console.log(false == null); // false
console.log(0 == null);    // false
console.log("" == null);    // false
console.log(NaN == null);    // false

console.log(undefined == null);    // true

This solution is perfectly functional. However, given that one side of an equality test is usually dynamically inserted, someone looking at your code may wonder if you are checking for undefined only or are purposely taking advantage of the loose equality operator’s flexibility.

If you are testing for both null or undefined, a more unambiguous solution is to state that in your code explicitly:

/*** A more explicit alternative to test for null and undefined ***/

console.log(undefined || null === null);     // true

Now, anyone looking at your code will be in no doubt that you are testing for null or undefined on the right-hand side.

Common exception #2: Intentionally ignoring type

It can be tempting to use the loose equality operator to deliberately ignore data type.

For example, imagine that you are aware that the incoming data will a number value in a string, and you want to check if it is equal to 0. You can use the loose equality operator to ignore type:

/*** "0" and 0 are the same in loose equality ***/

console.log("0" == 0);    // true

In this comparison, it works as expected. But if “0” is replaced by something else (as is often the case when working with data dynamically), the comparison can throw up some strange results

/*** "0" is the also same as false and NaN in loose equality  ***/

console.log("0" == false);    // true
console.log("0" == NaN);    // true

To avoid this, use the in-built parseInt method available on the Number object to convert the string to a number. If you then try the same comparisons, only the comparison between “0” and numeric 0 will return true.

/*** Using parseInt and strict equality achieves the same outcome while avoiding unexpected outcomes ***/

console.log(Number.parseInt("0") === 0);    // true
console.log(Number.parseInt("0") === false);    // false
console.log(Number.parseInt("0") === NaN);    // false

Summary

The loose equality operator tests for a difference in value only and ignores type. It achieves the by silently coercing the values being compared to be of the same type. The strict equality operator, on the other hand, returns true only if value and type match.

Because it does not coerce values, the strict equality operator returns much more predictable results. If you want to avoid unexpected errors, it is best to always use the strict equality operator.

But it is also good to know the common exceptions to the use of the strict equality operator, because this strategic use of the loose equality operator is commonplace in existing code bases.