Double Equal vs Triple Equal

Posted on February 04, 2019

This is part of a series where I try to explain through each of 33 JS Concepts.

This part corresponds to the Double Equal vs Triple Equal.

Prerequisites

  1. Type Coercion in JavaScript

That is all you need to know. No, I’m just kidding! But you do need to know that.

== is known as loose equality.

=== is known as strict equality.

What is difference between loose and strict?

Loose Equality performs Coercion.

Strict Equality does not perform Coercion.

Coercion is defined here follows the rules specified in the Abstract Equality Comparison Algorithm as defined in the ES Spec.

Case 1 - Both of the operands are of same types

Take Aways from here:

  1. NaN is not equal to itself or anything else.
  2. +0 is equal to -0 (not that anyone uses them)

Case 2 - The operands are null and undefined

These people are very special and they are coerced to be equal to each other.

Unlike others this is something that has constant applications. There might be functions that you want others to write and take the result from. You have instructed them to return null if the result is falsy but they forget. You have not got null, but you have got undefined in you hands. Instead of writing these an || to compare them you can compare the result with == to get the exact result you want.

This also means that they are not equal to anything else. If you try undefined == false, you are ought to get false out of it.

Don’t believe me? Try it out yourself.

Case 3 - One is string and the other number

The string is being converted into a number here. If it is not a number, you will get an NaN, which is not equal to anything else anyway (not even itself as we mentioned)

Case 4 - Boolean and something else

Huh? Where is the coercion I was promised?

Coercion is still happening, we are not just looking at it the way compiler is. If compiler sees a boolean on either side of the ==, it converts the boolean into a number and repeats the algorithm. So in our case, true gets converted to 1 and Is 12 == 1, No; and hence false

You know what would be right though? 1 == true, try it.

What if the other side is not a number? Say "12" == true, let’s break it down:

  1. Compiler sees a boolean: "12" == toNumber(true) —> "12" == 1
  2. Compiler sees a string: toNumber("12") == 1 —> 12 == 1 (Case 3)
  3. false

Case 5 - String/Number vs an Object

Lots of things here, let’s break them down one by one.

If we find an object on either sides of the == operator, we try converting it to a primitive.

How might we do that?

Objects have two methods defined to do this:

  1. toString()
  2. valueOf()

valueOf by default returns the object itself, toString says [object Object]

More like I’m Groot. But this time, annoying.

Rule 1: These two methods can only return primitives.

There are no errors if they return other stuff. It just ignores the value.

I mean, Common! valueOf just broke their only rule with it’s default value.

  1. Empty object is not a falsy value, no coercion here.

As we had mentioned in our Coercion article, arrays have a toString() function defined by default.

As == is a nuetral (default) case, compiler calls upon toString() on the array. which is join(','). What happens when we apply that function to an empty array? We get "", which is falsy.

Let’s recount the step the steps now:

  1. false gets converted to number (case 4) [] == 0
  2. [] toPrimitive called, toString is invoked "" == 0
  3. String and number (Case 3) 0 == 0 —> true

The same explanation explains 3, 4, 5 cases, so we will skip those.

6 asks the important question:

What if object has both valueOf and toString?

The compiler first makes some guesses about it.

Is it someplace a string would make sense? Like say, as an object key? Then prefer toString()

Is it somewhere a number would make sense? Like in a mathematical expression? Then valueOf

Is it someplace where both could exist? Like ==? Then valueOf anyway.

This is how the last one turns out to be false.

Can I get this hint the compiler makes and take a decision on it?

With ES6 and some magic with Symbols, yes you can.

See how it works

Case 6: Object vs Object

If the two objects compared are of same reference, then true otherwise false.

This is actually same for both == and ===, just making the point.

Does this change the way I code?

There is a choice to be made here. Stalwarts like Douglas Crockford, recommend that you should always use === instead of ==. There are people like Kyle Simpson who thinks understanding == would be a far better option.

There is an interesting conversation between Kyle Simpson and Brendan Eich on twitter about this:

To quote a Stackoverflow answer on the topic,

Douglas Crockford makes a lot of recommendations, but you don’t have to take them as gospel. :)

Have your opinion, have a team huddle, decide and code.

That’s about it about call stack for now. Is there something I missed? Something wrong? Something good? Ping me on Twitter