Skip to content

Commit dc02b8a

Browse files
authored
Reference for stage 4 iterator-sequencing (mdn#42671)
* Reference for stage 4 iterator-sequencing * Typos
1 parent 26cfe9e commit dc02b8a

File tree

3 files changed

+210
-1
lines changed

3 files changed

+210
-1
lines changed
Lines changed: 207 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,207 @@
1+
---
2+
title: Iterator.concat()
3+
short-title: concat()
4+
slug: Web/JavaScript/Reference/Global_Objects/Iterator/concat
5+
page-type: javascript-static-method
6+
browser-compat: javascript.builtins.Iterator.concat
7+
sidebar: jsref
8+
---
9+
10+
The **`Iterator.concat()`** static method creates a new {{jsxref("Iterator")}} object from a list of iterable objects. The new iterator yields the values from each of the input iterables in sequence.
11+
12+
## Syntax
13+
14+
```js-nolint
15+
Iterator.concat(it)
16+
Iterator.concat(it1, it2)
17+
Iterator.concat(it1, it2, /* …, */ itN)
18+
```
19+
20+
### Parameters
21+
22+
- `it1`, `it2`, …, `itN`
23+
- : An object that implements the [iterable](/en-US/docs/Web/JavaScript/Reference/Iteration_protocols#the_iterable_protocol) protocol. [Iterators](/en-US/docs/Web/JavaScript/Reference/Iteration_protocols#the_iterator_protocol) which are not also iterable cannot be passed directly to this method; they must first be wrapped using {{jsxref("Iterator.from()")}}.
24+
25+
### Return value
26+
27+
A new {{jsxref("Iterator")}} object that yields the values from each of the input iterables in sequence.
28+
29+
## Description
30+
31+
The `Iterator.concat()` method is conceptually similar to `Array`'s [`concat()`](/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/concat) method, but it operates on any kind of iterable, and returns an iterator instead of an array. This means that the iterables can be lazily iterated, avoiding unnecessary allocation or computation. It also means that, technically, you can [concatenate _infinite iterables_](#concatenating_infinite_iterables), but results from iterables after the first infinite iterable will never be reached.
32+
33+
While each iterable can be infinite, the list of iterables must be finite—and quite limited in number because engines impose a very low limit on the number of function arguments. If you need to concatenate a large—even infinite—number of iterables, use {{jsxref("Iterator.prototype.flatMap()")}} instead.
34+
35+
```js
36+
function* infiniteIterables() {
37+
for (let i = 1; ; i++) {
38+
yield Array(i).fill(i);
39+
}
40+
}
41+
42+
// BAD:
43+
// Iterator.concat(...infiniteIterables());
44+
// The spread operator never finishes
45+
46+
// GOOD:
47+
const it = infiniteIterables().flatMap((x) => x);
48+
// Infinite sequence of numbers: 1, 2, 2, 3, 3, 3, 4, 4, 4, 4, ...
49+
```
50+
51+
The `Iterator.concat()` method is similar in functionality to the following function, which uses the [`yield*`](/en-US/docs/Web/JavaScript/Reference/Operators/yield*) operator to yield values from each of the input iterables in sequence:
52+
53+
```js
54+
function* concat(...iterables) {
55+
for (const iterable of iterables) {
56+
yield* iterable;
57+
}
58+
}
59+
```
60+
61+
Like `yield*`, `Iterator.concat()` doesn't support arguments that are not iterable (i.e., doesn't have the `[Symbol.iterator]()` method). This is because `Iterator.concat()` always takes ownership over its iterators and [closes](/en-US/docs/Web/JavaScript/Reference/Iteration_protocols#returnvalue) open iterators when the method exits. With iterable arguments, `Iterator.concat()` acquires iterators one-by-one and just closes the current iterator when the iteration is stopped. With iterator arguments, it's not clear whether the caller or `Iterator.concat()` should be responsible for closing the iterators, especially the ones that `Iterator.concat()` hasn't reached, so the method simply disallows non-iterable arguments.
62+
63+
## Examples
64+
65+
### Combining maps
66+
67+
In this example, we create a new {{jsxref("Map")}} that's the union of three other maps. The {{jsxref("Map/Map", "Map()")}} constructor accepts an iterable of key-value pairs, while the [Map iterator](/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/Symbol.iterator) yields key-value pairs from the map, so just using `Iterator.concat()` on the maps is sufficient to create the new map.
68+
69+
```js
70+
const map1 = new Map([
71+
["a", 1],
72+
["b", 2],
73+
]);
74+
const map2 = new Map([
75+
["c", 3],
76+
["d", 4],
77+
]);
78+
const map3 = new Map([
79+
["a", 5],
80+
["e", 6],
81+
]);
82+
83+
const map = new Map(Iterator.concat(map1, map2, map3));
84+
console.log(map);
85+
// Map(5) {'a' => 5, 'b' => 2, 'c' => 3, 'd' => 4, 'e' => 6}
86+
```
87+
88+
Note that the value of key `"a"` in the resulting map is `5`. This is because the `Map` constructor uses the last value for each key.
89+
90+
### Concatenating infinite iterables
91+
92+
When any of the input iterables is infinite, the resulting iterator will also be infinite. This isn't immediately a problem because iterators can be consumed lazily and closed at any time, but it does mean that iterables after the first infinite iterable will never be reached.
93+
94+
```js
95+
function* it1() {
96+
yield 1;
97+
yield 2;
98+
}
99+
100+
function* it2() {
101+
let i = 3;
102+
while (true) {
103+
yield i++;
104+
}
105+
}
106+
107+
function* it3() {
108+
yield "done";
109+
}
110+
111+
const it = Iterator.concat(it1(), it2(), it3());
112+
for (const value of it.take(10)) {
113+
console.log(value); // 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
114+
}
115+
// "done" is never reached
116+
```
117+
118+
### Concatenating iterables of different types
119+
120+
You can concatenate iterables of different types.
121+
122+
```js
123+
const array = [1, 2, 3];
124+
const set = new Set([4, 5, 6]);
125+
function* gen() {
126+
yield 7;
127+
yield 8;
128+
yield 9;
129+
}
130+
131+
const it = Iterator.concat(array, set, gen());
132+
console.log([...it]); // [1, 2, 3, 4, 5, 6, 7, 8, 9]
133+
```
134+
135+
The elements of each iterable can also be of different types, just like arrays.
136+
137+
```js
138+
const array = [1, "two", 3];
139+
const set = new Set([true, {}]);
140+
141+
const it = Iterator.concat(array, set);
142+
console.log([...it]); // [1, "two", 3, true, {}]
143+
```
144+
145+
### Concatenating non-iterable objects
146+
147+
Non-iterable objects throw a `TypeError` when passed to `Iterator.concat()` because they don't have the `[Symbol.iterator]()` method.
148+
149+
```js
150+
const nonIterable = {
151+
next() {
152+
return { done: true };
153+
},
154+
};
155+
156+
const it = Iterator.concat(nonIterable); // TypeError: object is not iterable
157+
```
158+
159+
Because all built-in iterators extend the {{jsxref("Iterator")}} class, they are all iterable and can be passed to `Iterator.concat()`.
160+
161+
```js
162+
const arrayIterator = [1, 2, 3][Symbol.iterator]();
163+
164+
const it = Iterator.concat(arrayIterator); // No error
165+
```
166+
167+
To pass an iterator that isn't also iterable, you can wrap it using {{jsxref("Iterator.from()")}}.
168+
169+
```js
170+
const nonIterable = {
171+
next() {
172+
return { done: true };
173+
},
174+
};
175+
176+
const it = Iterator.concat(Iterator.from(nonIterable)); // No error
177+
```
178+
179+
Another option is to use {{jsxref("Iterator.prototype.flatMap()")}} instead, which automatically calls `Iterator.from()`. But be careful: you need to call `flatMap()` on an iterator, not on an array, because {{jsxref("Array.prototype.flatMap()")}} only supports array return values.
180+
181+
```js
182+
const nonIterable = {
183+
next() {
184+
return { done: true };
185+
},
186+
};
187+
188+
const it = [nonIterable].values().flatMap((x) => x); // No error
189+
```
190+
191+
When implementing your own iterators, consider making them iterable by or [subclassing `Iterator`](/en-US/docs/Web/JavaScript/Reference/Global_Objects/Iterator/Iterator#subclassing_iterator) or adding a `[Symbol.iterator]()` method that returns `this`.
192+
193+
## Specifications
194+
195+
{{Specifications}}
196+
197+
## Browser compatibility
198+
199+
{{Compat}}
200+
201+
## See also
202+
203+
- [Polyfill of `Iterator.concat` in `core-js`](https://github.com/zloirock/core-js#iterator-sequencing)
204+
- [es-shims polyfill of `Iterator.concat`](https://www.npmjs.com/package/es-iterator-helpers)
205+
- {{jsxref("Iterator")}}
206+
- {{jsxref("Iterator.from()")}}
207+
- {{jsxref("Array.prototype.concat()")}}

files/en-us/web/javascript/reference/global_objects/iterator/from/index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ The **`Iterator.from()`** static method creates a new {{jsxref("Iterator")}} obj
1212
## Syntax
1313

1414
```js-nolint
15-
from(object)
15+
Iterator.from(object)
1616
```
1717

1818
### Parameters

files/en-us/web/javascript/reference/global_objects/iterator/index.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,8 @@ const myIterator = Iterator.from({
137137

138138
## Static methods
139139

140+
- {{jsxref("Iterator.concat()")}}
141+
- : Creates a new `Iterator` object from a list of iterable objects. The new iterator yields the values from each of the input iterables in sequence.
140142
- {{jsxref("Iterator.from()")}}
141143
- : Creates a new `Iterator` object from an iterator or iterable object.
142144

0 commit comments

Comments
 (0)