Navigating Equality Comparators and Sameness Checks in JavaScript

when == != === and returns true instead of false

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 the 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 sameconsole.log(1 === '1'); //false because type is not the sameconsole.log('1' === '1'); //true because type and value is the sameconsole.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 sameconsole.log(1 == '1'); //true because after conversion, it is the sameconsole.log('1' == '1'); //true. No conversion needed but value is the same neverthelessconsole.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 numberconsole.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 numberconsole.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 themconsole.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 thingconsole.log(Object.is(itemX.x, itemX.x));//true because they're both pointing to the same thingconsole.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 were not explained here.