This proposal is officially in stage 1 of the TC39 process; the author believes it is ready to advance to stage 2, but has not yet had time to present to the committee.
This proposal was formerly for
Array.prototype.contains, but that name is not web-compatible. Per the November 2014 TC39 meeting, the name of both
Array.prototype.contains was changed to
includes to dodge that bullet.
When using ECMAScript arrays, it is commonly desired to determine if the array includes an element. The prevailing pattern for this is
if arr !== -1...
with various other possibilities, e.g.
arr.indexOf(el) >= 0, or even
These patterns exhibit two problems:
- They fail to "say what you mean": instead of asking about whether the array includes an element, you ask what the index of the first occurrence of that element in the array is, and then compare it or bit-twiddle it, to determine the answer to your actual question.
- They fail for
indexOfuses Strict Equality Comparison and thus
[NaN].indexOf(NaN) === -1.
We propose the addition of an
Array.prototype.includes method, such that the above patterns can be rewritten as
This has almost the same semantics as the above, except that it uses the SameValueZero comparison algorithm instead of Strict Equality Comparison, thus making
Thus, this proposal solves both problems seen in existing code.
We additionally add a
fromIndex parameter, similar to
String.prototype.includes, for consistency.
includes instead of
If you survey existing APIs,
has is used for conceptual "keys," whereas
includes is used for conceptual "values." That is:
- Keys inside a key-value map:
- Sets, whose elements are conceptually both keys and values:
- Strings, which are conceptually maps from indices to code points:
The best consistency here is with
String, not with
The web has classes like DOMStringList and DOMTokenList which are array-like, and have methods named
contains with the same semantics as our
includes. Unfortunately, meshing with those is not web-compatible, as explained above; we will have to accept this inconsistency.
String.prototype.includes works on strings, not characters!?
Yes, that's true. The best way to think about this is that
String.prototype.includes behave like their
Array.prototype counterparts in the special case of a single character. But the string versions can also be used in the more general case of a larger string.
So in this way, the relationship between
Array.prototype.includes is the same as the relationship between
There are four equality algorithms in the current ES6 draft:
- Abstract Equality Comparison (
- Strict Equality Comparison (
===): used by
- SameValueZero: used by
ArrayBufferconstructors, as well as
- SameValue: used in all other places
(Note however that most places SameValue is used could be replaced by SameValueZero since those places often never compare primitives, or at least never compare numbers.)
Using Abstract Equality Comparison would be bonkers, of course. Using SameValue is not a good idea for the same reasons it is not used by
-0s can sneak into your code fairly easily via arithmetic operations, but you almost always desire
-0 to be treated the same as
+0, so distinguishing them will just cause spurious failures.) This leaves Strict Equality Comparison and SameValueZero as the two possibilities.
SameValueZero is generally the better choice, as it allows you to detect if an array includes a
NaN. The argument for Strict Equality Comparison boils down to "bug compatibility" with
Array.prototype.indexOf. But one of the purposes of
Array.prototype.includes is to steer users away from creating these sort of bugs.
This introduces a slight refactoring hazard from
Array.prototype.includes: they will indeed behave differently for arrays containing
NaNs. However, it seems much more likely that code will become less buggy via this refactoring, instead of causing problems. Introducing a new method, and accompanying it with the appropriate messaging around this case, should help.