Skip to content
This repository was archived by the owner on Nov 17, 2020. It is now read-only.

Commit 4b6b953

Browse files
committed
Rename from "contains" to "includes"
Per the November 2014 TC39 meeting, we're going to try doging the web-compatibility problems by using the name "includes" instead.
1 parent 4fafe65 commit 4b6b953

36 files changed

+183
-185
lines changed

README.md

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
1-
# `Array.prototype.contains` Proposal
1+
# `Array.prototype.includes` Proposal
22

33
## Status
44

55
This proposal is officially in stage 1 of [the TC39 process](https://docs.google.com/document/d/1QbEE0BsO4lvl7NFTn5WXWeiEIBfaVUF7Dk0hpPpPDzU/edit); the author believes it is ready to advance to stage 2, but has not yet had time to present to the committee.
66

7-
However, its further advancement is blocked by the fact that [it is not web-compatible](http://esdiscuss.org/topic/having-a-non-enumerable-array-prototype-contains-may-not-be-web-compatible). There are [thoughts](http://esdiscuss.org/topic/array-prototype-contains-solutions) of how we could work toward a solution, but nothing is clear yet.
7+
This proposal was formerly for `Array.prototype.contains`, but that name [is not web-compatible](http://esdiscuss.org/topic/having-a-non-enumerable-array-prototype-contains-may-not-be-web-compatible). Per the November 2014 TC39 meeting, the name of both `String.prototype.contains` and `Array.prototype.contains` was changed to `includes` to dodge that bullet.
88

99
## Motivation
1010

11-
When using ECMAScript arrays, it is commonly desired to determine if the array contains an element. The prevailing pattern for this is
11+
When using ECMAScript arrays, it is commonly desired to determine if the array includes an element. The prevailing pattern for this is
1212

1313
```js
1414
if (arr.indexOf(el) !== -1) {
@@ -20,44 +20,44 @@ with various other possibilities, e.g. `arr.indexOf(el) >= 0`, or even `~arr.ind
2020

2121
These patterns exhibit two problems:
2222

23-
- They fail to "say what you mean": instead of asking about whether the array contains 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.
23+
- 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.
2424
- They fail for `NaN`, as `indexOf` uses Strict Equality Comparison and thus `[NaN].indexOf(NaN) === -1`.
2525

2626
## Proposed Solution
2727

28-
We propose the addition of an `Array.prototype.contains` method, such that the above patterns can be rewritten as
28+
We propose the addition of an `Array.prototype.includes` method, such that the above patterns can be rewritten as
2929

3030
```js
31-
if (arr.contains(el)) {
31+
if (arr.includes(el)) {
3232
...
3333
}
3434
```
3535

36-
This has almost the same semantics as the above, except that it uses the SameValueZero comparison algorithm instead of Strict Equality Comparison, thus making `[NaN].contains(NaN)` true.
36+
This has almost the same semantics as the above, except that it uses the SameValueZero comparison algorithm instead of Strict Equality Comparison, thus making `[NaN].includes(NaN)` true.
3737

3838
Thus, this proposal solves both problems seen in existing code.
3939

40-
We additionally add a `fromIndex` parameter, similar to `Array.prototype.indexOf` and `String.prototype.contains`, for consistency.
40+
We additionally add a `fromIndex` parameter, similar to `Array.prototype.indexOf` and `String.prototype.includes`, for consistency.
4141

4242
## FAQs
4343

44-
### Why `contains` instead of `has`?
44+
### Why `includes` instead of `has`?
4545

46-
If you survey existing APIs, `has` is used for conceptual "keys," whereas `contains` is used for conceptual "values." That is:
46+
If you survey existing APIs, `has` is used for conceptual "keys," whereas `includes` is used for conceptual "values." That is:
4747

4848
- Keys inside a key-value map: `Map.prototype.has(key)`, `WeakMap.prototype.has(key)`, `Reflect.has(target, propertyKey)`
4949
- Sets, whose elements are conceptually both keys and values: `Set.prototype.has(value)`, `WeakSet.prototype.has(value)`, `Reflect.Loader.prototype.has(name)`
50-
- Strings, which are conceptually maps from indices to code points: `String.prototype.contains(searchString, position)`
50+
- Strings, which are conceptually maps from indices to code points: `String.prototype.includes(searchString, position)`
5151

5252
The best consistency here is with `String`, not with `Map` or `Set`.
5353

54-
Finally, the web has classes like [DOMStringList](https://developer.mozilla.org/en-US/docs/Web/API/DOMStringList) and [DOMTokenList](http://dom.spec.whatwg.org/#interface-domtokenlist) which are array-like, and have methods named `contains` with the same semantics. Meshing with those, and in the case of `DOMStringList` potentially replacing them, is a nice side benefit.
54+
The web has classes like [DOMStringList](https://developer.mozilla.org/en-US/docs/Web/API/DOMStringList) and [DOMTokenList](http://dom.spec.whatwg.org/#interface-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.
5555

56-
### But `String.prototype.contains` works on strings, not characters!?
56+
### But `String.prototype.includes` works on strings, not characters!?
5757

58-
Yes, that's true. The best way to think about this is that `String.prototype.indexOf` and `String.prototype.contains` 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.
58+
Yes, that's true. The best way to think about this is that `String.prototype.indexOf` and `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.
5959

60-
So in this way, the relationship between `String.prototype.contains` and `Array.prototype.contains` is the same as the relationship between `String.prototype.indexOf` and `Array.prototype.indexOf`.
60+
So in this way, the relationship between `String.prototype.includes` and `Array.prototype.includes` is the same as the relationship between `String.prototype.indexOf` and `Array.prototype.indexOf`.
6161

6262
### Why SameValueZero?
6363

@@ -72,21 +72,21 @@ There are four equality algorithms in the current ES6 draft:
7272

7373
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 `Map` and `Set`. (Briefly: `-0`s 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.
7474

75-
SameValueZero is generally the better choice, as it allows you to detect if an array contains 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.contains` is to steer users away from creating these sort of bugs.
75+
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.
7676

77-
This introduces a slight refactoring hazard from `Array.prototype.indexOf` to `Array.prototype.contains`: they will indeed behave differently for arrays containing `NaN`s. 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.
77+
This introduces a slight refactoring hazard from `Array.prototype.indexOf` to `Array.prototype.includes`: they will indeed behave differently for arrays containing `NaN`s. 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.
7878

7979
## Illustrative Examples
8080

8181
```js
82-
assert([1, 2, 3].contains(2) === true);
83-
assert([1, 2, 3].contains(4) === false);
82+
assert([1, 2, 3].includes(2) === true);
83+
assert([1, 2, 3].includes(4) === false);
8484

85-
assert([1, 2, NaN].contains(NaN) === true);
85+
assert([1, 2, NaN].includes(NaN) === true);
8686

87-
assert([1, 2, -0].contains(+0) === true);
88-
assert([1, 2, +0].contains(-0) === true);
87+
assert([1, 2, -0].includes(+0) === true);
88+
assert([1, 2, +0].includes(-0) === true);
8989

90-
assert(["a", "b", "c"].contains("a") === true);
91-
assert(["a", "b", "c"].contains("a", 1) === false);
90+
assert(["a", "b", "c"].includes("a") === true);
91+
assert(["a", "b", "c"].includes("a", 1) === false);
9292
```

package.json

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,20 @@
11
{
2-
"name": "array.prototype.contains",
2+
"name": "array.prototype.includes",
33
"version": "1.0.0",
4-
"description": "Tests and a polyfill for the ES proposal for Array.prototype.contains",
4+
"description": "Tests and a polyfill for the ES proposal for Array.prototype.includes",
55
"main": "reference-implementation/index.js",
66
"scripts": {
77
"test": "test262-harness --prelude=reference-implementation/index.js --consoleCommand=\"node --harmony\" --runner=console test/*.js"
88
},
9-
"repository": {
10-
"type": "git",
11-
"url": "https://github.com/domenic/Array.prototype.contains.git"
12-
},
9+
"repository": "domenic/Array.prototype.includes",
1310
"keywords": [
1411
"ecmascript",
1512
"array",
1613
"test262",
17-
"contains"
14+
"contains",
15+
"includes"
1816
],
19-
"author": "Domenic Denicola <[email protected]> (http://domenic.me/)",
17+
"author": "Domenic Denicola <[email protected]> (https://domenic.me/)",
2018
"license": "BSD-2-Clause",
2119
"devDependencies": {
2220
"test262-harness": "bterlson/test262-harness"

reference-implementation/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# `Array.prototype.contains` Reference Implementation
1+
# `Array.prototype.includes` Reference Implementation
22

33
The reference implementation is meant to be a line-by-line transcription of the specification from ECMASpeak into JavaScript, as much as is possible.
44

reference-implementation/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ var ToString = require("especially/abstract-operations").ToString;
99
var abs = require("especially/math").abs;
1010
var define_built_in_data_property = require("especially/meta").define_built_in_data_property;
1111

12-
define_built_in_data_property(Array.prototype, "contains", function contains(searchElement) {
12+
define_built_in_data_property(Array.prototype, "includes", function includes(searchElement) {
1313
var fromIndex = arguments[1];
1414

1515
var O = ToObject(this);

spec.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
# Array.prototype.contains ( searchElement [ , fromIndex ] )
1+
# Array.prototype.includes ( searchElement [ , fromIndex ] )
22

3-
NOTE `contains` compares _searchElement_ to the elements of the array, in ascending order, using the SameValueZero algorithm, and if found at any position, returns **true**; otherwise, **false** is returned.
3+
NOTE `includes` compares _searchElement_ to the elements of the array, in ascending order, using the SameValueZero algorithm, and if found at any position, returns **true**; otherwise, **false** is returned.
44

55
The optional second argument _fromIndex_ defaults to 0 (i.e. the whole array is searched). If it is greater than or equal to the length of the array, **false** is returned, i.e. the array will not be searched. If it is negative, it is used as the offset from the end of the array to compute _fromIndex_. If the computed index is less than 0, the whole array will be searched.
66

7-
When the `contains` method is called, the following steps are taken:
7+
When the `includes` method is called, the following steps are taken:
88

99
1. Let _O_ be the result of calling ToObject passing the **this** value as the argument.
1010
1. ReturnIfAbrupt(_O_).
@@ -26,4 +26,4 @@ When the `contains` method is called, the following steps are taken:
2626
1. Increase _k_ by 1.
2727
1. Return **false**.
2828

29-
The `length` property of the `contains` method is **1**.
29+
The `length` property of the `includes` method is **1**.

test/Array.prototype.contains_function-name.js

Lines changed: 0 additions & 11 deletions
This file was deleted.

test/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# `Array.prototype.contains` Tests
1+
# `Array.prototype.includes` Tests
22

33
These tests are written in test262 format. To run them against the reference implementation (which only works in Node 0.11), do
44

test/Array.prototype.contains_adding-getter.js renamed to test/adding-getter.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// This code is governed by the BSD license found in the LICENSE file.
33

44
/*---
5-
description: Array.prototype.contains sees a new element added by a getter that is hit during iteration
5+
description: Array.prototype.includes sees a new element added by a getter that is hit during iteration
66
author: Domenic Denicola
77
---*/
88

@@ -15,7 +15,7 @@ var arrayLike = {
1515
}
1616
};
1717

18-
var result = Array.prototype.contains.call(arrayLike, 'c');
18+
var result = Array.prototype.includes.call(arrayLike, 'c');
1919

2020
if (result !== true) {
2121
$ERROR('Expected array-like to contain "c", which was added by the getter for the 1st element');

test/Array.prototype.contains_array-like.js renamed to test/array-like.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,30 +2,30 @@
22
// This code is governed by the BSD license found in the LICENSE file.
33

44
/*---
5-
description: Array.prototype.contains works on array-like objects
5+
description: Array.prototype.includes works on array-like objects
66
author: Domenic Denicola
77
---*/
88

99
var arrayLike1 = { length: 5, 0: "a", 1: "b" };
1010

11-
var result1 = Array.prototype.contains.call(arrayLike1, "a");
11+
var result1 = Array.prototype.includes.call(arrayLike1, "a");
1212
if (result1 !== true) {
1313
$ERROR('Expected array-like to contain "a"');
1414
}
1515

16-
var result2 = Array.prototype.contains.call(arrayLike1, "c");
16+
var result2 = Array.prototype.includes.call(arrayLike1, "c");
1717
if (result2 !== false) {
1818
$ERROR('Expected array-like not to contain "c"');
1919
}
2020

2121
var arrayLike2 = { length: 2, 0: "a", 1: "b", 2: "c" };
2222

23-
var result3 = Array.prototype.contains.call(arrayLike2, "b");
23+
var result3 = Array.prototype.includes.call(arrayLike2, "b");
2424
if (result3 !== true) {
2525
$ERROR('Expected array-like to contain "b"');
2626
}
2727

28-
var result4 = Array.prototype.contains.call(arrayLike2, "c");
28+
var result4 = Array.prototype.includes.call(arrayLike2, "c");
2929
if (result4 !== false) {
3030
$ERROR('Expected array-like to not contain "c"');
3131
}

test/Array.prototype.contains_exception-before-match.js renamed to test/exception-before-match.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// This code is governed by the BSD license found in the LICENSE file.
33

44
/*---
5-
description: Array.prototype.contains should terminate if getting an index throws an exception
5+
description: Array.prototype.includes should terminate if getting an index throws an exception
66
negative: Test262Error
77
includes: [Test262Error.js]
88
---*/
@@ -17,4 +17,4 @@ var trappedZero = {
1717
}
1818
};
1919

20-
Array.prototype.contains.call(trappedZero, 'a');
20+
Array.prototype.includes.call(trappedZero, 'a');

0 commit comments

Comments
 (0)