How Comparisons Work in JavaScript: A Thorough Guide

How Comparisons Work in JavaScript: A Thorough Guide

I read some parts of the JS book series 'You Don't Know JS' by Kyle Simpson a few years ago. Now there is a 2nd edition in progress and I started re-reading it. As the author himself recommends, these books should be read several times. They need to be digested properly as the content is quite heavy. So I read again the chapter about comparison and this is my attempt to write down what I have learned.

What's the difference between == and ===?

You might get this asked when you apply for a front-end developer position. Triple-equals === is more strict, you may answer. It means that === doesn't allow coercion, that is conversion of a value type from one to another. Here is an example:

'2' == 2  => true 
'2' === 2 => false

Nice. I think it's a pretty sufficient answer. But oh dear, there's so much more to it. Let's review more Javascript basics. There are primitive value types and objects. Common primitives are:

  • String

  • Number

  • Boolean

  • Null

  • Undefined

As objects we can classify Arrays and even functions.

Comparing primitive values

We can use typeof operator to check a type. In some cases you won't get what you would expect though.

typeof(null) => 'object'

This operator is useful when we make comparisons. Consider the following example:

const num1 = 9007199254740992;
const num2 = 9007199254740992n;

num1 == num2    => true
num1 === num2   => false

It's barely noticeable, but if we checked the types, we could see the num2 is actually of type bigint, whereas num is number;

typeof(num2) => bigint

So it's clear by now that both == and === compare the values and the types, but == checks the type and converts it if necessary before comparing it.

All value comparisons in JS consider the type of the values being compared, not just the === operator. Specifically, === disallows any sort of type conversion (aka, "coercion") in its comparison, where other JS comparisons do allow coercion.

Triple-equals have also a few edge case scenarios, where it doesn't behave as expeceted.

NaN === NaN;    => false
0 === -0;       => true

To check these values, we can use Number.isNaN() method. It's interesting to note there is another way to compare values, which doesn't give us those misleading answers. It's Object.is() and it returns correct values.

Object.is(null, null);  => true
Object.is(NaN, NaN) => true

Comparing objects

What about more complex scenarios involving objects? How do we compare them? As you noticed with primitive types, we were comparing 2 values like 4 === "4". Objects have usually nested properties and we can't compare them by their structure or content (structural equality). Look at this object for example:

let books = {
  title: 'Climate Library',
  list: [
    {
      id: 1,
      name: ''Speed & Scale",
      author: "John Doerr",
      published: "October 28th 2021"
    },
    {
      id: 2,
      name: ''A New Earth - The Apocalypse Locus",
      author: "George Tsakraklides ",
      published: "November 8th 2021"
    }
  ]
}

Comparing { a: 2 } === { a: 2 } yields false, besides the example above. (if we tried to compare it with another object). Why is that?

In JS, all object values are held by reference, are assigned and passed by reference-copy, and to our current discussion, are compared by reference (identity) equality.

We can have another variable favouriteBooks and assign it a value of books. Then we can compare them like this:

let books = {...};
let favouriteBooks = {};
favouriteBooks = books;

books === favouriteBooks   => true

favouriteBooks refers to the same object books so comparing them returns true.

Other comparisons

Keep in mind there are other relational comparison operators like <, >, <= and >=. We use them in if conditions, loops and other places and the conversion of value type applies also there so watch out.

Conclusion

We learned that even simple Javascript comparison hides many nitty-gritty details under the surface. Should we use == or ===? It depends. Double equality does convert the types! We could see that Object.is() is an even stricter way to compare 2 values though. I feel like I left out a lot of information and I would have to read it again and again to absorb it fully. Check out the book and as Appendix B says: Practice, Practice, Practice!