We have all been there… You compare two values using `==`

, receive a totally unexpected result and wonder *WTF* is going on?! - Just Equality `==`

operator at its finest.

Equality `==`

operator has the following syntax.

x == y

It takes two operands, `x`

and `y`

, converts them into the same type, compares them by value and returns a `Boolean`

result.

Always use Strict Equality `===` operator. There is literally no benefit in using `==` instead of `===`, except if your goal is to introduce bugs to your codebase.

But you did not come here so I can tell you to start using `===`

. Just look at the code below. You want to know how it can possibly be explained, don't you? - And yes, you should know it. After all, you are working with JavaScript and this is a JavaScript feature.

1'' == '0' // Result: false20 == '' // Result: true30 == '0' // Result: true45false == undefined // Result: false6false == null // Result: false7null == undefined // Result: true89[] == 0 // Result: true10[] == '0' // Result: false11['a', 'b'] == 'a,b' // Result: true1213NaN == NaN // Result: false14'\n\r\t' == 0 // Result: true

## IsLooselyEqual algorithm

When you use `==`

, under the hood, this algorithm kicks in and gives the result of comparison. So, yes, here lies the cure for our pain.

This algorithm is described in ECMAScript specification and basically every JavaScript engine has to implement it as described.

It is common to represent algorithms with some kind of graph or flow chart, but since I am very bad at drawing, I present to you this magnificent pseudocode.

1Take two operands, `x` and `y`, as an input23If type of `x` is the same as type of `y`4 If type of `x` is `Undefined`5 return `true`6 If type of `x` is `Null`7 return `true`89 If type of `x` is `Number`10 If `x` is `NaN`11 return `false`12 If `y` is `NaN`13 return `false`14 If `x` is the same as `y`15 return `true`16 If `x` is `-0` and `y` is `+0`17 return `true`18 if `x` is `+0` and `y` is `-0`19 return `true`20 return `false`2122 If the type of `x` is `String`23 If `x` and `y` are exactly the same sequence of characters24 return `true`25 return `false`2627 If the type of `x` is `Boolean`28 If `x` and `y` are both `true`29 return `true`30 If `x` and `y` are both `false`31 return `true`32 return `false`3334 If `x` and `y` refer to the same object35 return `true`3637 return `false`3839If `x` is `null` and `y` is `undefined`40 return `true`41If `x` is `undefined` and `y` is `null`42 return `true`.4344If type of `x` is `Number` and type of `y` is `String`45 Convert `y` to `Number`46 Return the result of the comparison `x == y`47If type of `x` is `String` and type of `y` is `Number`48 Convert `x` to `Number`49 Return the result of the comparison `x == y`5051If type of `x` is `Boolean`52 Convert `x` to `Number`53 Return the result of the comparison `x == y`54If type of `y` is `Boolean`55 Convert `y` to `Number`56 Return the result of the comparison `x == y`5758If type of `x` is either `String` or `Number` and type of `y` is `Object`59 Convert `y` to primitive value60 Return the result of the comparison `x == y`61If type of `x` is `Object` and type of `y` is either `String` or `Number`62 Convert `x` to primitive value63 Return the result of the comparison `x == y`6465Return `false`

Keep in mind that some parts of the algorithm are missing in pseudocode representation. If you want to see detailed specifications, check it out on ECMAScript website.

Yes, I know, it's just a bunch of if statements and conversions. This conversion part is really what's important. You see, when types are the same, `==`

behaves exactly the same as the `===`

operator. Important difference is that `==`

enforces coercion when types are different.

Coercion is a fancy JavaScript term used when we talk about converting from one value type to another, like from string to number. Coercion plays an important role in `==`

comparison.

If you don't want to remember the whole algorithm, think about it in this way. If operands do not have the same type, they are converted to `Number`

. When types are the same, operands are compared by value.

## Object to primitive

One more important thing, before we focus on some examples, is conversion of the `Object`

type values to primitive values.

In JavaScript, there are 7 primitive values: *string*, *number*, *bigint*, *boolean*, *undefined*, *null* and *symbol*.

Value with the type of `Object`

can automatically be converted to primitive value by `==`

operator. This conversion will happen when the type of one operand is `Object`

while the other operand has one of primitive types.

When converting `Object`

to primitive value, JavaScript will do a couple of things. It will first try to call the built-in prototype method `valueOf`

. If `valueOf`

does not return a primitive value, the built-in prototype method `toString`

will be called next.

As almost anything in JavaScript this behavior has a couple of edge cases and it can be modified and overridden, but you don't have to worry about it for now.

## Examples

Still remember that code sample from the beginning? Let's cover it line by line, now when we know how the algorithm works.

I will make one assumption here. Operand on the left side of `==`

will be called `x`

and the operand on the right side will be called `y`

. With that out of the way, let's get started.

Keep in mind, if operands do not have the same type, `==`

will enforce **type conversion** as long as operands have different types. Only then will operands be compared by value.

### Sample 01

'' == '0' // Result: false

This one is pretty simple. Both operands have the same type, `String`

. This means that operands will be compared by value. Since values are not the same, the result is `false`

.

Look at IsLooselyEqual algorithm on line: `3, 22 - 24`

.

### Sample 02

0 == '' // Result: true

Type of operand `x`

is `Number`

and type of operand `y`

is `String`

. Types are not the same and `y`

will be converted to `Number`

.

Empty string `''`

converted to `Number`

, will be `0`

. Test it by running `Number('')`

in your browser's console.

When conversion is completed operands will be compared by value. Since values are the same, `0`

is indeed equal to `0`

, result will be `true`

.

Look at IsLooselyEqual algorithm on line: `44 - 46`

.

### Sample 03

0 == '0' // Result: true

Type of operand `x`

is `Number`

and the type of operand `y`

is `String`

. Operand `y`

will be converted to `Number`

.

When `'0'`

is converted to `Number`

, its value is going to be `0`

. Test it by running `Number('0')`

in your browser's console.

When conversion is completed operands will be compared by value. Since values are the same, `0`

is indeed equal to `0`

, result will be `true`

.

Look at IsLooselyEqual algorithm on line: `44 - 46`

.

### Sample 04

false == undefined // Result: falsefalse == null // Result: falsenull == undefined // Result: true

I grouped these examples together since the reasoning for this behavior, in all of them, is pretty much the same.

According to the algorithm, `undefined`

can only be equal to `undefined`

or `null`

. Same is for `null`

, it can only be equal to `null`

or `undefined`

. Because of this, comparing them to `false`

will always result in `false`

.

Look at IsLooselyEqual algorithm on line: `3 - 7, 39 - 42, 65`

.

### Sample 05

[] == 0 // Result: true

Operand `x`

is the type of `Object`

and the type of operand `y`

is `String`

. As we already know, before they can be compared by value, type conversion is going to happen. In this case, operand `x`

will be converted to a primitive value. This means `Object`

to primitive conversion will kick in.

So, let's see how the conversion of `[]`

to primitive value looks like. Method `valueOf`

is going to be called on `[]`

directly. Test it by running `[].valueOf()`

in your browser's console. The result of this operation will be `[]`

.

As you can see, we still have `[]`

which is not a primitive value, so method `toString()`

gets called. Test it by running `[].toString()`

in your browser's console. Returned value is `''`

which is a primitive value. With this, conversion of `Object`

to primitive value is finally completed.

But, look closely, operands still have different types, `x`

is now `''`

which is type `String`

and `y`

is still `0`

which is type `Number`

. Conversion must continue.

Now, `x`

will be converted to `Number`

. We already know, from previous examples, that `''`

is going to be `0`

after conversion. When conversion is completed operands will be compared by value. Since values are the same, `0`

is indeed equal to `0`

, result will be `true`

.

Look at IsLooselyEqual algorithm on line: `61 - 63`

.

### Sample 06

[] == '0' // Result: false

Operand `x`

is type of `Object`

, but operand `y`

is type of `String`

. Operand `x`

, with value `[]`

, will be converted to primitive value. We already know, from Sample 05, the result of this conversion is going to be empty string `''`

. After conversion, operand `x`

will have value `''`

and type `String`

.

Since both operands are now the same type, `String`

, conversion is completed. When compared by value, `''`

is not the same as `'0'`

, so this comparison is `false`

.

Look at IsLooselyEqual algorithm on line: `61 - 63`

.

### Sample 07

['a', 'b'] == 'a,b' // Result: true

Operand `x`

is type of `Object`

and operand `y`

is type of `String`

. In the conversion step, `Object`

will be converted to primitive value.

After conversion, operand `x`

will have value `'a,b'`

and type `String`

. Test it by running `['a', 'b'].toString()`

in your browser's console.

Both operands are now types of `String`

. When compared by value, the result is `true`

, since values are the same.

Look at IsLooselyEqual algorithm on line: `61 - 63`

.

### Sample 08

NaN == NaN // Result: false

This one is quite strange and yet simple. Comparing any value with `NaN`

is always going to result in `false`

. This is the case even if `NaN`

is compared to `NaN`

, which seems quite weird.

Look at IsLooselyEqual algorithm on line: `3, 9 - 13`

.

### Sample 09

'\n\r\t' == 0 // Result: true

Operands have different types, so conversion is required. Since the type of `x`

is `String`

it will be converted to `Number`

. After conversion, `'\n\r\t'`

will be `0`

. Now, when compared by values, `0`

is the same as `0`

, so the result is `true`

.

Look at IsLooselyEqual algorithm on line: `47 - 49`

.

If you are wondering how `'\n\r\t'`

, after conversion, can become `0`

- it's because of how conversion to `Number`

works.

There are some special Single Character Escape Sequences like `\n`

(new line), `\t`

(horizontal tab), `\v`

(vertical tab), `\r`

(carriage return) that are always going to be `0`

when converted to `Number`

. It does not matter in which order and how many of them are contained inside the same string value.

## Conclusion

We all know JavaScript can be weird, but if you look a bit under the hood, things can become much clearer. The same thing is with the Equality `==`

operator. On the surface it can be really strange, but when you know the algorithm behind it, things can become much easier to understand.

Either way, I strongly recommend **always using** the Strict Equality `===`

operator. But don't get me wrong, it is still really important to know how `==`

works. It is, after all, a JavaScript feature which is always going to be part of the language.