Specs
This appears to be part of the Number::sameValueZero abstract operation:
6.1.6.1.15 Number::sameValueZero ( x, y )
- If x is NaN and y is NaN, return true.
[...]
This operation is required to be part of the Array#includes() check which does:
22.1.3.13 Array.prototype.includes ( searchElement [ , fromIndex ] )
[...]
- Repeat, while k < len
 a. Let elementK be the result of ? Get(O, ! ToString(k)).
 b. If SameValueZero(searchElement, elementK) is true, return true.
 c. Set k to k + 1.
- Return false.
[...]
Where the SameValueZero operation will delegate to the one for numbers at step 2:
7.2.12 SameValueZero ( x, y )
[...]
- If Type(x) is different from Type(y), return false.
- If Type(x) is Number or BigInt, then
 a. Return ! Type(x)::sameValueZero(x, y).
- Return ! SameValueNonNumeric(x, y).
For comparison Array#indexOf() will use Strict Equality Comparison which is why it behaves differently:
const arr = [NaN];
console.log(arr.includes(NaN)); // true
console.log(arr.indexOf(NaN));  // -1
 
 
Other similar situations
Other operations that use SameValueZero for comparison are in sets and maps:
const s = new Set();
s.add(NaN);
s.add(NaN);
console.log(s.size);     // 1
console.log(s.has(NaN)); // true
s.delete(NaN);
console.log(s.size);     // 0
console.log(s.has(NaN)); // false
 
 
const m = new Map();
m.set(NaN, "hello world");
m.set(NaN, "hello world");
console.log(m.size);     // 1
console.log(m.has(NaN)); // true
m.delete(NaN);
console.log(m.size);     // 0
console.log(m.has(NaN)); // false
 
 
History
The SameValueZero algorithm first appears in the ECMAScript 6 specifications but it is more verbose. It still has the same meaning and still has an explicit:
7.2.10 SameValueZero(x, y)
[...]
- If Type(x) is Number, then
a. If x is NaN and y is NaN, return true.
[...]
ECMAScript 5.1 only has a SameValue algorithm which still treats NaN equal to NaN. The only difference with SameValueZero is how +0 and -0 are treated: SameValue returns false for them, while SameValueZero returns true.
SameValue is mostly used for internal object operation, so it is almost inconsequential for writing JavaScript code. A lot of the uses of SameValue are when working with object keys and there are no numeric values.
The SameValue operation is directly exposed in ECMAScript 6 as that is what Object.is() uses:
console.log(Object.is(NaN, NaN)); // true
console.log(Object.is(+0, -0));   // false
 
 
Of slight interest is that WeakMap and WeakSet also use SameValue rather than SameValueZero that Map and Set use for comparison. However, WeakMap and WeakSet only allow objects as unique members, so attempting to add a NaN or +0 or -0 or other primitives leads to an error.