Exploring How Operators Are Compared in JavaScript

Exploring How Operators Are Compared in JavaScript

When two operators are compared or matched in JavaScript, the internal evaluation process depends on the type of comparison operator being used. This includes strict equality (===), loose equality (==), and relational operators (<, >, etc.). JavaScript uses a mix of type conversion, value comparison, and algorithmic steps to determine the result. Let’s dive into the details.

1. Equality Operators

Loose Equality (==)

The == operator compares two values for equality after performing type coercion (it is the process of automatically or explicitly converting a value from one data type to another, such as from a string to a number or vice versa in JavaScript) if they are of different types. JavaScript follows these steps internally:

  1. Same Type: If the values are of the same type, compare them directly:

    • 1 == 1true (both are numbers).

    • 'hello' == 'hello'true (both are strings).

  2. Different Types:

    • String and Number: Convert the string to a number, then compare.

        '5' == 5Number('5') == 55 == 5true
        // Again
        5 == '5'5 == Number('5') → 5 == 5true
      
    • Boolean and Non-Boolean: Convert the boolean to 1 (for true) or 0 (for false), then compare.

        true == 11 == 1true
        false == 00 == 0true
      
    • null and undefined:

      • null == undefined → true

        • == (loose equality) compares values without considering their types, so null and undefined are considered equal in this case. This is an exception in JavaScript where they are loosely equal to each other.
        null == undefinedtrue
  • null == 0 → false

    • null is not equal to 0 because == performs type coercion. JavaScript does not convert null to 0 when compared with ==.
  • null >= 0 and null <= 0

    • null >= 0 → true and null <= 0 → true because when null is coerced to a number, it becomes 0. So, null is treated as 0 and thus both comparisons evaluate to true.
  • null > 0 and null < 0

    • null > 0 → false and null < 0 → false because null coerces to 0, and 0 is neither greater than nor less than 0.
        // null is not equal to 0
        console.log(null == 0); // false

        // null is coerced to 0 in numeric comparison
        console.log(null >= 0); // true
        console.log(null <= 0); // true
        console.log(null > 0); // false
        console.log(null < 0); // false
  • undefined == 0 → false

    • undefined == 0 is false because undefined cannot be converted to a numeric value when compared using ==. Therefore, they are not equal.
  • undefined >= 0, undefined <= 0, undefined > 0, undefined < 0

    • Comparisons involving undefined (like undefined >= 0, undefined <= 0, etc.) will result in false in JavaScript because undefined cannot be coerced into a number and return NaN and thus cannot be compared to numeric values. So all these comparisons evaluate to false.
        // undefined is not equal to 0
        console.log(undefined == 0); // false

        // undefined cannot be compared with numbers
        console.log(undefined >= 0); // false
        console.log(undefined <= 0); // false
        console.log(undefined > 0); // false
        console.log(undefined < 0); // false
  • Object and Primitive: Convert the object to its primitive equivalent using valueOf() or toString() and then compare.

      [1] == 1'1' == 1Number('1') == 11 == 1true
    

    Another Example:

      [1, 'Hridoy', 45, true] == '4,5'  // '1,Hridoy,45,true' == '4,5' → false
    

    Explanation:

    • The array [1, 'Hridoy', 45, true] is converted to a string by calling its toString() method, which results in the string '1,Hridoy,45,true'.

    • The comparison is then between the string '1,Hridoy,45,true' and the string '4,5'.

    • Since these two strings are not equal, the result of the comparison is false.

Notes:

  • No type conversion happens if both values are null or undefined; they are considered equal only to each other.

  • NaN is not equal to any value, including itself.

Strict Equality (===)

The === operator checks for equality without type coercion. Both the value and the type must be identical for the comparison to return true.

  1. Same Type: If the values are of the same type, compare them directly:

    • 5 === 5true (same type and value).

    • 'abc' === 'abc'true (same type and value).

  2. Different Types: If the types are different, the result is always false:

     '5' === 5false
     true === 1false
    
  3. Special Cases:

    • NaN === NaNfalse (NaN is not equal to itself).

    • 0 === -0true (both are considered equal in JavaScript).

2. Relational Operators (<, >, <=, >=)

Relational operators convert the operands to primitives (if needed) and compare their values using a numeric or lexicographic comparison, depending on the type.

Steps for Relational Comparisons:

  1. Primitive Conversion:

    • If the operands are objects, JavaScript calls their valueOf() or toString() methods to get primitive values.

    • Example:

        let obj = { valueOf: () => 5 };
        console.log(obj > 3); // true
      
  2. String vs. String:

    • Strings are compared lexicographically (character by character based on Unicode values).
    'apple' < 'banana'true (based on dictionary order)
    '5' > '12'true (because '5' comes after '1' lexicographically)
  1. String and Number:

    • Convert the string to a number and perform a numeric comparison.
    '5' > 2Number('5') > 25 > 2true
  1. Non-Primitives:

    • Convert objects to primitives, then compare.
    [5] < 10Number([5]) < 105 < 10true
  1. Edge Cases:

    • Comparing null or undefined to a number converts null to 0 and undefined to NaN.
    null < 10 < 1true
    undefined < 1NaN < 1false

3. Logical Operators (&&, ||, !)

Logical operators (&&, ||, !) return one of the operands rather than a boolean in some cases. They follow short-circuit evaluation.

Steps:

  1. Logical AND (&&):

    • If the first operand is falsy, return it.

    • Otherwise, return the second operand.

    0 && 'hello'0
    true && 'world''world'
  1. Logical OR (||):

    • If the first operand is truthy, return it.

    • Otherwise, return the second operand.

    null || 'hello''hello'
    'world' || 0'world'
  1. Logical NOT (!):

    • Converts the operand to a boolean and negates it.
    !truefalse
    !0true

4. Primitive Conversion Details

ToPrimitive Conversion:

JavaScript attempts to convert objects to primitives during comparison:

  1. Calls valueOf() first.

  2. If valueOf() returns a non-primitive, calls toString().

  3. Throws an error if neither produces a primitive.

let obj = { 
    valueOf: () => 5, 
    toString: () => '10' 
};

console.log(obj > 3); // true (uses valueOf())
console.log(obj + ''); // '5' (uses valueOf())
  • console.log(obj > 3);

    • The expression obj > 3 involves a comparison operation. When comparing objects with numbers, JavaScript tries to convert the object to a primitive (number) for the comparison.

      • obj.valueOf() returns 5, so the expression becomes 5 > 3, which is true.
    • Result: true.

  • console.log(obj + '');

    • In this case, JavaScript is concatenating the object with an empty string ('').

      • obj.toString() returns '10', so the expression becomes '10' + '', which results in '10'.
    • Result: '10'.