Equality Comparators (==) and Sameness Checks (===) in JavaScript

Equality checks is one of those things we all end up doing — mostly because we can’t avoid if else statements unless we try really hard.

The difference between == and === often stumps a lot of new JavaScript developers because on surface they look the same and most of the time produce the same result — until it doesn’t.

Here’s a concise run down on the difference between == and ===.

And as a bonus, I’m going to throw in Object.is() as well because it’s also an equality comparitor that no one really talks about.

Let us begin with the triple equal ===

=== aka Strict Equality

The triple equal (===) got its name because it compares two values as is. There is no type conversion. If the values you’re comparing are numbers, then you’re considered equal if they are the same and not NaN.

NaN are always considered unequal and will return false, even if the compared value is also NaN. This is partly because the comparitor doesn’t know if the compared value has the same type or not.

Here are some example scenarios and it’s expected output.

console.log(1 === 1); //true because type and value is same
console.log(1 === '1'); //false because type is not the same
console.log('1' === '1'); //true because type and value is the same
console.log(null === undefined); 
//false because null is an assignment value and undefined hasn't been declared yet.

== aka Loose equality

The big difference between strict and loose equality is that the later converts values into a common type before the comparison is made. While === does no conversion at all and performs the comparison as is, == converts the value and determines sameness based on that.

So, using the previous examples, here are the new outputs.

console.log(1 == 1); 
//true because value is same

console.log(1 == '1'); 
//true because after conversion, it is the same

console.log('1' == '1'); 
//true. No conversion needed but value is the same nevertheless

console.log(null == undefined); 
//true because at the end of the day, null and undefined don't exist

Things starts to get interesting with == when you start throwing objects into the mix.

let thisIsAnObject = new String('item');
let thisIsAString = 'item';

console.log(thisIsAnObject == thisIsAString);
//true. Because after conversion, semantically, it's the same.

console.log(thisIsAnObject === thisIsAString);
//false. Because there is no conversion and type is different despite having the same value.

For Boolean values == converts it to 1 and 0.

console.log(true == 1); //returns true 
console.log(true === 1); //returns false because types are different

For string and boolean combination, the string value gets converted into a numeric value.

console.log(true == 'true'); 
//returns false because string can't be transformed into a number

console.log(true == '1');
//returns true because '1' can be converted into a numeric value

What about objects and boolean? The object gets converted into a primitive type and if it ends up being a number, then it has a chance of throwing the correct and expected output.

let x = new String('1');
let y = new String('true');

console.log(x == true); //true. x can be converted to a number
console.log(y == true); // false. y can't be converted into a number

//both console logs will return false if === is used because type is different.

Object.is()

Object.is is similar in nature to === but does not behave in the exact same way.

Like === it doesn’t transform the value but treats the evaluation of +0 and -0 differently from ===.

console.log(0 === +0); 
//true because === sees no difference between them

console.log(Object.is(0, +0));
false because it is not an exact match

So where does +0 and -0 come in useful? When you hit potential edge cases in Math related outputs. In these cases, +0 and -0 become real problems and potential bugs if you use === instead of Object.is

The question then becomes, in what scenario would you ever use it? Perhaps if you were developing a game that required velocity calculations or stopping force to be taken into consideration. Or perhaps you’re drawing something in JavaScript with math functions.

Object.is also has another potentially useful functionality in that it checks if the object is exactly the same. Not just based on value but actual referencing.

console.log(Object.is([], [])); 
//false. Although both are objects, they're not referencing the exact same object.

let itemX = { x: 'woop' };
let itemY = { x: 'woop' };

console.log(Object.is(itemX, itemY));
//false. Although both look the same, the parameters are not referencing the same thing

console.log(Object.is(itemX.x, itemX.x));
//true because they're both pointing to the same thing

console.log(itemX.x == itemY.x); 
console.log(itemX.x === itemY.x);
//both will return true because they both look the same. Location is not taken into account. 

Object.is is just something for you to keep in mind and know that it exists.

And that Object.is is not supported in Internet Explorer.

Final words

Hopefully this has cleared up any confusion or mysterious differences in output between == and ===, and help reduce potential bugs caused by equality operators. Sometimes things look the same but the situation and scenario in which they are use also determine their final outcome.

If you’re interested, here’s an equality table to help you decrypt scenarios that was not explained here.