JavaScript’s Equality Operator
By: Owen Haupt
Tags: Coding, Programming, JavaScript, Web Development, Ecmascript

JavaScript’s Equality Operator

A Story about Type Conversion

When it comes to the equality operator, figuring out how JavaScript handles type conversion can be difficult. Having a better understanding — or at least having a reference to come back to — can have a positive impact on your coding and better prepare you for the mysteries and unintended side effects of type conversion.

This article hopes to be that reference, both for you and myself. Let’s start with some definitions!

Strict equality

Strict equality ( === , often == in other languages) is familiar for most programmers. It checks whether or not two values are identical and of the same type.

Operand

An object/value we use in an operation. In 5 == '5' , there are two operands – 5 and '5' .

Type conversion

Type conversion is the transfer of data from one data type to another. This can happen implicitly (when the compiler automatically assigns data types) or explicitly (when your code tells JavaScript to perform a conversion). When a conversion occurs automatically, as with the equality operator, we also refer to the process as type coercion. Let’s see this in action.

The Equality Operator

The equality operator ( == ) performs type conversion when comparing operands. This can be useful when comparing values that look similar but are of different types.

One such case is checking numbers against strings that look like numbers.

5 == '5'; // true

It is somewhat clear what is happening, here. The string is being converted into a number, then strict equality is being checked…right? Maybe! Maybe the number is being converted into a string? In this post, I will provide concrete examples and descriptions of questions like these surrounding type conversion.

5 == ‘5’

The ECMAScript specification can be confusing to read. It almost reads like a mathematics research paper. When I wanted to get the low-down on the equality operator, I went to the source. Below, I’ll construct an easy-to-follow protocol to help you determine how abstract equality works in several scenarios.

NOTE: Some steps will have an explicit return (e.g. #2):

– return true Others will output a new abstract equality operation, instead (e.g. # 3):

– 5 == 5; The resulting operands are brought back up to Step #1, where the algorithm is repeated until an explicit return is reached.

Abstract Equality Comparison Algorithm

Updated for ECMA2020.

For x == y, follow these steps:

1. If x and y are of the same type, return x === y

5 === 5; => true

'foo' === 'bar'; => false

false === false; => true

null === undefined; => false

{ foo: 'bar' } === { foo: 'bar' }; => false

2. If x is null and y is undefined (or vice-versa), return true

null == undefined; => true

3. If x is a String and y is a Number (or vice-versa), convert the String to a Number

'5' == 5;

=> convert '5' to Number

=> Number('5') => 5 5 == 5;

4. If x is a BigInt and y is a String (or vice-versa), convert the String to a BigInt

BigInt(5) == '5';

=> convert '5' to BigInt

=> Bigint('5') BigInt(5) == BigInt('5');

5. If x or y is a Boolean, convert it to a Number

true == 3;

=> convert true to Number

=> Number(true) => 1 1 == 3; false == 'foo';

=> convert false to Number

=> Number(false) => 0 0 == 'foo';

6. If x is either a String, Number, BigInt, or Symbol, and y is an Object (or vice-versa), attempt to convert the Object into a Primitive

Sometimes, objects have built-in/pre-defined methods that help with conversion to Primitives. Such methods are out of the scope of this article, and we will ignore these special cases — we will use a simple object,

{ foo: 'bar' } , for this step.

’baz’ == { foo: 'bar' };

5 == { foo: 'bar' };

BigInt(5) == { foo: 'bar' };

Symbol('baz') == { foo: 'bar' };

In each of these cases, the object’s toString method is used for conversion. The default behavior of this method simply returns the string '[object Object]' .

[String/Number/BigInt/Symbol] == { foo: 'bar' };

=> convert object using .toString()

=> { foo: 'bar' }.toString() => '[object Object]' [String/Number/BigInt/Symbol] == '[object Object]';

7. If x is a BigInt and y is a Number (or vice-versa):

If either x or y is NaN , +∞ , or -∞ , return false

BigInt(5) == NaN; => false

BigInt(5) == Infinity; => false

BigInt(5) == -Infinity; => false

If neither x nor y is NaN , +∞ , or -∞ , complete Strict Equality for the mathematical values of x and y

BigInt(5) == 5;

=> Number(BigInt(5)) => 5 5 === 5; => true BigInt(5) == 3;

=> Number(BigInt(5)) => 5 5 === 3; => false