One of the things we all do every day while programming is comparing values — whether they’re equal, different, greater, lesser, etc. — in order to take actions based on them.
Many times in JavaScript we get comparison results we didn’t expect, and this can lead to bugs in our code. That’s why I think it’s important to understand the algorithm the language uses for this.
21 == '21' // true
undefined == null // true
undefined === null // false
{} === {} // false
NaN === NaN // false
[10] == 10 // true
21 < '22' // true
[22] > [21] // true
Let’s go step by step and understand this.
There are two main types of comparisons: equalities and inequalities. The result of any of these is a boolean (true or false) reflecting the relationship between the evaluated values.
One of the things that makes this mechanism complex is coercion, which converts data types based on their usage context (if the conversion is possible).
If you don’t understand this mechanism, you might get some unexpected results without knowing why.
let num = '24'; //String
let explicita = Number(num); //number
let implicita = num * 2; //num ahora se usa como number
There are values that are implicitly converted to false. These are:
'' // (string vacio)
0, -0, NaN
null, undefined
Since this is a somewhat extensive topic, it will be covered in more detail in a dedicated post later.
Another mechanism used in comparisons is the conversion of objects to primitives, when they’re compared to a primitive value.
Types in JavaScript are divided into primitives and reference types — Understanding types in JavaScript
The mechanism followed for this conversion is:
- If valueOf(..) can be used, it’s called and returns a primitive value.
- If .toString(..) can be used, it’s called and returns a primitive value.
- In other cases, it returns an error.
The mechanism that’s normally used is toString().
Types of Comparisons
Equalities
These evaluate whether two values are equal. The following operators are used:
== , === → Igual
!= , !== → No igual
The ! is used to denote negation, meaning not equal
== vs ===
The === operator is often known as strict equality, having a behavior closer to what we’d expect. But beyond that, it’s good to know the algorithm for both types of equality.
Algorithm for ==
When two values are evaluated with this operator, the following sequence is followed to determine the result:
- If they are the same type, they’re tested with
=== - If they are different types:
2.1 If one is null and the other is undefined, it returns true.
2.2 If one is a string and the other a number, the string is converted, and they’re evaluated as numbers.
2.3 If one is a boolean, it’s transformed — true becomes 1 and false becomes 0 — and they’re evaluated.
2.4 If one is an object and the other a number or string, the object is converted to a primitive.
- In other cases, it returns false.
You can check this algorithm in the specification, section 11.9.3
null == undefined // true, caso 2.1
10 == '10' // true, caso 2.2
true == 1 // true, caso 2.3
[10] == 10 // true, caso 2.4
[] == [] // false, caso 3
Algorithm for ===
This equality is stricter with its results, using the following sequence to determine the result:
- If they have different types, it returns false
- If both are null, it returns true
- If both are undefined, it returns true
- If one or both are NaN, it returns false
- If both are true or false, it returns true
- If both are number and have the same value, it returns true
- If both are string and have the same value, it returns true
- In other cases, it returns false
You can check this algorithm in the specification, section 11.9.6
21 === "21" // false, caso 1
undefined === null // false, caso 1
NaN === NaN // false, caso 4
[10] == 10 // false, caso 1
true == 1 // false, caso 1
[] === [] //false, caso 8
'10' === '10' //true, caso 7
Here are some things to keep in mind when deciding which operator to use:
- If either of the values is a boolean, use
=== - If you’re not sure whether the values are converted by coercion, use
=== - In other cases, you can safely use
==
By convention and as a best practice, the community promotes the use of ===
Inequalities
The result of evaluating an inequality is always a boolean.
The following operators are used to compare inequalities:
< → Menor
> → Mayor
<= → Menor Igual
>= → Mayor Igual
They’re usually used for numbers, but they also work for strings.
- If either is an object, it’s converted to a primitive and evaluated.
- If both are string, the characters are evaluated alphabetically.
- If both are number, they’re evaluated.
- In other cases, the result is false
You can check this algorithm in the specification, section 11.8.5
[10] < 9 // false, caso 1
"a" < "b" // true, caso 2
10 >= 10 // true, caso 3