SameValueZero Equality in JavaScript

SameValueZero is a JavaScript equality algorithm that treats `NaN` as equal to `NaN` and treats `+0` and `-0` as equal. It is used by operations such as `Set`, `Map` key matching, and `Array.prototype.includes()`.

SameValueZero is one of JavaScript's internal equality algorithms. Unlike strict equality (`===`), it considers `NaN` equal to itself. This matters because `NaN === NaN` is `false`, while SameValueZero matching can successfully find a `NaN` value.

SameValueZero also treats `+0` and `-0` as equal. This matches the behavior of `===`, even though `Object.is(+0, -0)` distinguishes the two signed zeros.

You normally encounter SameValueZero indirectly rather than calling it yourself. `Array.prototype.includes()` uses it to search arrays, and `Set` and `Map` use the same matching semantics for values and keys. This makes `NaN` behave naturally as a stored or searchable value in these APIs.

The distinction is important when choosing an equality operation. Use `===` for ordinary strict comparisons, `Object.is()` when the distinctions around `NaN` and signed zero matter, and remember SameValueZero when reasoning about collection membership and key matching.

Key points

Interview questions

What is SameValueZero in JavaScript?

SameValueZero is an equality algorithm used by several JavaScript collection and search operations. It treats `NaN` as equal to itself, unlike `===`. It also considers `+0` and `-0` equal.

Why does `[NaN].includes(NaN)` return `true` while `[NaN].indexOf(NaN)` returns `-1`?

`includes()` uses SameValueZero for element matching, so `NaN` matches another `NaN`. `indexOf()` uses strict-equality-style comparison, where `NaN` does not equal itself. Therefore `includes()` returns `true`, while `indexOf()` fails to find the element and returns `-1`.

How does SameValueZero affect `Set` and `Map`?

`Set` uses SameValueZero-style value matching when determining whether an element already exists. `Map` uses the same matching semantics for keys. Consequently, a `NaN` key can be retrieved using another `NaN`, and `+0` and `-0` identify the same key.

Compare `===`, `Object.is()`, and SameValueZero.

All three are distinct equality algorithms with different edge-case behavior. `===` does not consider `NaN` equal to itself and considers the signed zeros equal. `Object.is()` considers `NaN` equal to itself but distinguishes `+0` and `-0`. SameValueZero matches `NaN` with itself and treats the signed zeros as equal.

Can you demonstrate the practical difference between `includes()` and `indexOf()`?

Yes. For an ordinary value such as `2`, both can locate the element. For `NaN`, `includes(NaN)` returns `true` because SameValueZero considers the values equal. `indexOf(NaN)` returns `-1` because its comparison does not treat `NaN` as equal to itself.