Dark Truth of  Abstract Equality (==) & Strict Equality (===) ... (Hidden Facts with proof)

Dark Truth of Abstract Equality (==) & Strict Equality (===) ... (Hidden Facts with proof)

Introduction

Comparison operators are used in conditional expressions to determine which block of code executes, thus controlling the program flow. Comparison operators compare two values in an expression that resolves to a value of true or false.

In Javascript also we have many comparison operators but but out of those all, there are two comparison operators which are almost similar but differ by very few thin lines drawn by developers of Javascript. I hope you guessed it right I am talking about == & === operators. These two operators have names as well one is having fixed name i.e strict equality operator === & second one has two names just like the official name and nickname i.e Abstract equality operator == . People also call == as a loose equality operator. Both operators check equality but with certain differences. Checking equality is so simple but people always get confused about these two operators.

  1. "==" equality checks for value

  2. "===" equality checks for both value and datatype.
    Abstract equality ( == )check only values and Strict equality ( === )checks both type and values. Is it Correct ???

Many of you will think this is the correct statement and there are a bunch of articles and blogs you will see this is the correct statement,
But actually, the answer is NO NO NO NO, this is an absolutely wrong statement. This is the misconception many people have. Am I proving it wrong no The actual JS Documentation proves it wrong and I am going to brief here everything you need to know about == & ===, So let's go step by step let's understand first Abstract equality and Strict equality and then see the difference in working of both.

 const myRollNo = 23;
 console.log(typeof myRollNo); /* "number" */
 const str = "23";
 console.log(typeof str); /* "string" */
 console.log(myRollNo == str);   /* true */
 console.log(myRollNo === str);  /* false */

With the above approach, it seems that there is an issue with Abstract Equality == and many will say there is an issue with this but

When there is a difference between what we think and what JS Does, there appears the bug

Now Let's understand how things work so basically Type Coercion is a fundamental pillar of Javascript and how it works behind the scene.

What the hell is Type Coercion Now ??

Javascript has 4 fundamental pillars which make javascript a best in the game i.e

  1. Coercion

  2. Object Oriented Programming

  3. Scopes

  4. Asynchronous Programming

Type coercion is nothing but the conversion of data types.

Type Coercion can happen in two ways -

  • Explicit Coercion - When there is a change in the data type intentionally(on purpose) by the author of the code, then it is said to be explicit coercion.

      const num = 23;
      const strNum = String(num); // '23'
      console.log(typeOf(num)); // Number
      console.log(String(num)); // '23'
      console.log(typeof(num)); // Number;
      console.log(Number(strNum)); // 23
      console.log(typeOf(strNum)); //String
    
  • Implicit Coercion - When there is a change in the data type happens automatically by the language itself. Javascript implicitly performs automatic type conversion as needed.

      const name = 'Akash';
      const age = 22;
      console.log(name+age); // Akash22
    
      /* In the above code we are addinng two variable name and age. If one of the operand is a string then other operand is automatically converted to 
       the string data type. In the above code, name  data type is a string and age data type is number which is converted to string automatically by implicit coercion. */
    

Abstract Equality ==

Abstract equality operator == is also referred to as a loose equality operator returns a boolean value of true or false based on comparison i.e if both values are equal it returns true or else returns false . That's it that's the working of an Abstract equality operator you must be thinking it's almost similar to whatever we read in other blogs but wait my dear readers.

Real working of Abstract equality works differently :

  • It checks the Type of both operands and if the type is the same it performs a Strict Equality operation over those two operands which we will see later.

If the type of both operands is not the same it performs Type Coercion Implicitly based on Algorithm which is as follows:

DISCLAIMER - Don't get overwhelmed by word algorithim just think it as bunch of steps which gets followed internally

These are the steps that get followed internally when Abstract Equality == used over operand x & y when we use x==y

  1. So what happens here when we use == operator, it performs a type check as shown in the first step. If both the type is same Javascript internally calls Strict Equality Comparison Steps x === y.

  2. If the left operand i.e x here is null and the right operand i.e y is undefined then it returns true .

  3. If the left operand i.e x here is undefined and the right operand i.e y is null then it returns true .

    That's why when we do console.log(undefined==null) we get true but I saw many people tells it as a weird behaviour of Javascript. Now with the above steps, we got the understanding this is no weird behaviour in spite it's mentioned in such a way that it will return true .

  4. The most awaited point came up what if one operand is a number and one operand is a string so if we see the 4th step in the above image we can see that if the left operand i.e x is of type number and right operand i.e y is of type string,
    Js does internal type coercion and converts the right operand which is the string data type to a number type and then after type conversion, it returns the result of x == y & again and now both x and y type is the same i.e number type then it will perform strict equality === over x and y as explained in step 1.

  5. Same as above what if again one operand is a number and one operand is a string so if we see the 5th step in the above image we can see that if the left operand i.e x is of type string and right operand i.e y is of type number,
    Js does internal type coercion and converts the left operand which is the string data type to a number type and then after type conversion, it returns the result of x == y & again and now both x and y type is the same i.e number type then it will perform strict equality === over x and y as explained in step 1.

  6. What if one operand is Boolean type and another operand is non-boolean (string,number,undefined,null,symbol) type value then javascript internally does implicit type coercion and converts boolean data type value.

    1. If the left operand i.e x is Boolean type value and Y is non-boolean (string,number,undefined,null,symbol) type then x will be converted internally to a Number type value and then x == y is performed and the result is returned. (Refer to the 6th point in the above image)

    2. If the left operand i.e x is non-boolean (string,number,undefined,null,symbol) type value and Y is Boolean type value then y will be converted internally to a Number type value and then x == y is performed and the result is returned.

      (Refer to the 7th point in the above image)

       console.log(true == 'true') // false 
       /* Many places you will find the explanation that boolean true will be type coercied to string and then check will happen but that is wrong explanation what happens here let's see this : 
       1 - both types are not equal so step 1 is ruled out
       2 - one operand is boolean so now boolean operand will be converted   to number type so Number(true) --> 1  and now check will happen with 
       1=='true'
       3 - Now again when 1 == 'true' is checked 
          3.1 Type is not same so step 1 will be ruled out again.
          3.2 One type is number and other type is string so string type  will be converted into number and when we convert string 'true' to a number Number('true') it returns NaN (not a valid number). and again  
         1== NaN get's performed.
       4 - Now see 1 is of type number and NaN is also of type number so both are same type and now since both are of same type strict equality operation get's called 1 === NaN and since left operand i.e 1 is not equal to right operand i.e NaN , hence it returns result as False. */
       /* 
       I hope I was able to explain the example well if any doubts please do put it out in comment section I will try to resolve it
        */
      
  7. The 7th point explanation is the same as the 6th point.

  8. So what happens when one of the operands is of type String, Number or Symbol or Boolean gets compared with a non-primitive value i.e with an object then the Javascript converts the non-primitive value to a primitive value using an abstract operation let's not get deep dive into that as it's in itself a big discussion which I will discuss in later blogs. so it converts the object into a valid primitive value and then performs abstract equality (==) over it.

    1. If left operand i.e X is String or Number or Symbol & right operand i.e y is an object than y will be converted into primitive data type and then it performs x==y .

    2. If left operand i.e X is an object & right operand i.e y is an String or Number or Symbol than x will be converted into primitive data type and then it performs x==y .

Now Let's Move to Strict Equality === Operator -

Strict Equality Operator ===

Strict equality is the most widely used in the codebases. The main reason for its high usage is due to the lack of knowledge of people regarding Abstract equality so since now we have a better understanding of Abstract equality == let's decipher how Strict Equality works -

So this is the basic working of === operator :

  1. It checks the type of both the operand and if the type of both operands is different then it returns false .

  2. Since both the operand are of the same type then If one operand is Number

    1. If x is NaN it returns false.

    2. If y is NaN it returns false.

       /*  If anyone of the operand is NaN then it returns false. */
      
       /*
       So You might have come across this question
       console.log(NaN ===NaN)  prints false why ?
       */
       /* Ans -
       The reason is simple since both left operand and right operand is of same type Number then it checks if any of the operand is NaN  it returns false.
      
       Disclaimer  -  NaN is the only value of number type which is not equal to itself
      
       */
      
    3. If the left operand x and right operand y are both of the same value it returns true.

    4. If the left operand i.e x is 0 and the right operand i.e y is -0 it returns true.

    5. If the left operand i.e x is -0 and the right operand i.e y is 0 it returns true.

    6. If none of the above steps is validated then it returns simply false .

So Now we got an understanding of both Abstract Equality == & Strict Equality === .
We understood how things work and Basically, we demystified the fact that Javascript is not weird it's the beauty and magic of Javascript and its pillar.

Conclusion

So now we know very well that nothing in Javascript is weird. Some people think Coercion is a boon to Javascript but according to me it's not a boon if we know and understands it very well.

Now a valid point comes up when to use == & when to use === ?

so we see in large codebases and in many organizations, we use Strict Equality === which is a very good thing to do. According to me if we are not sure on what data value we are applying equality checks then it's recommended to use === .

If you want to experience power or coercion you can use == .

I hope after reading this your confusion regarding == & === will get over still, if you have some doubts please ask in the comment section, and I'll be happy to clear your doubts.

References -