Blog articles

Abstract vs Strict equality in Javascript

February 11, 2016

Testing for equality is fundamental in computer science. And while it seems like a straightforward concept (Thing A is the same as Thing B, or it isn’t) there are some subtleties that can, at first, seem strange. For example, it seems a common source of confusion for those new to javascript is whether to use == or === when making an equality comparison. This post will explain the difference between these two operators and how to decide when to use one over the other.

First, some terminology about Javascript string equals: Double equals is officially known as the abstract equality comparison operator while triple equals is termed the strict equality comparison operator. The difference between them can be summed up as follows: Abstract equality will attempt to resolve the data types via type coercion before making a comparison. Strict equality will return false if the types are different. Consider the following example:

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

Using two equal signs returns true because the string “3” is converted to the number 3 before the comparison is made. Three equal signs sees that the types are different and returns false. Here’s another:

console.log(true == '1'); // true
console.log(true === '1'); // false

Again, the abstract equality comparison performs a type conversion. In this case both the boolean true and the string ‘1’ are converted to the number 1 and the result is true. Strict equality returns false.
If you understand that you are well on your way to distinguishing between == and ===. However, there’s some scenarios where the behavior of these operators is non intuitive. Let’s take a look at some more examples:

console.log(undefined == null); // true
console.log(undefined === null); // false. Undefined and null are distinct types and are not interchangeable.
console.log(true == 'true'); // false. A string will not be converted to a boolean and vice versa.
console.log(true === 'true'); // false

The example below is interesting because it illustrates that string literals are different from string objects.

console.log("This is a string." == new String("This is a string.")); // true
console.log("This is a string." === new String("This is a string.")); // false

To see why strict equality returned false, take a look at this:

console.log(typeof "This is a string."); // string
console.log(typeof new String("This is a string.")); //object

The new operator will always return an object and you will get the same results when comparing primitive numbers and booleans to their respective object wrappers.
Reference types
Speaking of objects, what happens if we want to compare reference types? Do abstract and strict comparison behave any differently when we are dealing with objects? Yes! There is another rule you need to keep in mind. When comparing reference types both abstract and strict comparisons will return false unless both operands refer to the exact same object. Consider the following:

var a = [];
var b = [];
var c = a;
console.log(a == b); // false
console.log(a === b); // false
console.log(a == c); // true
console.log(a === c); // true

Even though a and b are of the same type and have the same value, both abstract and strict equality return false.

So which one should I use?

Keep it strict. Using the strict equality operator by default will increase the clarity of your code and prevent any false positives caused by abstract equality comparison. When you need to compare values of different types, do the conversions yourself. The more explicit your code, the better.

Digging deeper

For more on this topic, take a look at the ECMAScript Language Specification. Also check out this nifty table showing all possible type comparisons. Finally, see this post by mozilla for a comprehensive discussion of equality and sameness.