# Equality in JavaScript

Nov 3, 2020

JavaScript defines 4 different algorithms for determining whether two values are equal:

1. Abstract equality: `==`
2. Strict equality: `===`
3. SameValue: `Object.is()`
4. SameValueZero: Same as `Object.is`, except `-0` is considered equal to `+0`.

## Strict Equality, SameValueZero, SameValue

Strict equality, SameValueZero, and SameValue are almost equivalent. They only differ in their handling of `NaN`, `+0`, and `-0`. For all other values, the last 3 algorithms are identical.

Strict Equality: `NaN` is not strictly equal to any value, not even itself. In other words, `NaN !== NaN`. Also, `(+0) === (-0)`.

SameValue: The `Object.is()` function implements the SameValue algorithm. With the SameValue algorithm, `NaN` is equal to itself: `Object.is(NaN, NaN) === true`. But, on the other hand, `+0` is not equal to `-0`: `Object.is(+0, -0) === false`.

SameValueZero: There's no way to use SameValueZero directly, but the `Array#includes()` method uses SameValueZero internally. So, to try out SameValueZero, you can use `includes()`. The only difference between SameValue and SameValueZero is that SameValueZero treats `+0` as equal to `-0`: `[+0].includes(-0) === true`.

As a developer, you should typically use `===`, with the understanding that you may need to add a special case if you care about `NaN`. The distinction between `+0` and `-0` is not important for most use cases.

## Abstract Equality

Abstract equality has numerous differences. The abstract equality algorithm supports several implicit type conversions. Here's a brief overview:

1. If `x` and `y` are the same type, check if `x === y`.
2. If `x` and `y` are both either `null` or `undefined`, return `true`.
3. If `x` is a number and `y` is a string, convert `y` to a number and then compare using `===`. Similarly, if `x` is a boolean or string, and `y` is a number, convert `x` to a number.
4. If `x` or `y` is a boolean, convert the other value of a number and compare them.
5. If `x` is an object and `y` is a symbol, string, or number, try to convert `x` to a primitive using valueOf() and then compare using `===`.

In general, you should not use abstract equality. The one potential exception is checking for nullish values:

``````// Only true if `v === null` or `v === undefined`
v == null;

// Equivalent:
v === null || v === undefined;``````

## Where These Equality Comparisons Are Used

The tricky part of these different equality comparisons is that different JavaScript methods use different equality algorithms internally. For example, the `Array#indexOf()` function uses strict equality, but `Array#includes()` uses SameValueZero, which leads to different behavior when searching for `NaN` in arrays:

``````[NaN].indexOf(NaN); // -1, not found!

[NaN].includes(NaN); // true, found!``````

Here's where these different equality comparisons are used:

1. Strict Equality: `indexOf()`, `lastIndexOf`, `case` statements.
2. SameValueZero: `Set` values, `Map` keys, `includes()`.
3. SameValue: Used internally by `Object.defineProperty()`.