What is an iterator?
What an iterator is
An iterator is an object that returns elements of a sequence one at a time on each call to its .next() method.
Formal definition:
An iterator is an object implementing a
next()method that returns an object of the shape{ value: any, done: boolean }
What an iterator looks like by hand
function createIterator(arr) {
let i = 0;
return {
next() {
if (i < arr.length) {
return { value: arr[i++], done: false };
} else {
return { value: undefined, done: true };
}
}
};
}
const iterator = createIterator(['a', 'b', 'c']);
console.log(iterator.next()); // { value: 'a', done: false }
console.log(iterator.next()); // { value: 'b', done: false }
console.log(iterator.next()); // { value: 'c', done: false }
console.log(iterator.next()); // { value: undefined, done: true }When done: true, the iteration ends.
What an iterator does inside for...of
When you write:
for (const item of ['a', 'b', 'c']) {
console.log(item);
}Under the hood, JavaScript does roughly this:
const iterable = ['a', 'b', 'c'];
const iterator = iterable[Symbol.iterator](); // creates an iterator
while (true) {
const { value, done } = iterator.next();
if (done) break;
console.log(value);
}What an iterable object is
An object is iterable if it has a method:
obj[Symbol.iterator]()that returns an iterator.
Examples of built-in iterable structures:
ArrayStringMapSetargumentsNodeList(in the browser)TypedArray
Example: your own iterable object
const range = {
from: 1,
to: 4,
[Symbol.iterator]() {
let current = this.from;
let last = this.to;
return {
next() {
if (current <= last) {
return { value: current++, done: false };
} else {
return { done: true };
}
}
};
}
};
for (const num of range) {
console.log(num); // 1, 2, 3, 4
}When JS encounters for...of, it calls range[Symbol.iterator]() and uses the returned iterator.
Example: a string is iterable too
const str = "Hi";
const iterator = str[Symbol.iterator]();
console.log(iterator.next()); // { value: 'H', done: false }
console.log(iterator.next()); // { value: 'i', done: false }
console.log(iterator.next()); // { value: undefined, done: true }Iterators + Spread / Destructuring / Array.from
All of these constructs use an iterator internally:
const set = new Set([1, 2, 3]);
console.log([...set]); // [1, 2, 3]
console.log(Array.from(set)); // [1, 2, 3]
const [a, b] = set;
console.log(a, b); // 1 2What Symbol.iterator does
Symbol.iterator is a special symbol that defines whether an object is "iterable". JS calls this method automatically whenever it needs to iterate the object (for...of, spread, and so on).
Generators = automatic iterators
A generator (function*) is a function that creates its own iterator.
function* numbers() {
yield 1;
yield 2;
yield 3;
}
const iterator = numbers();
console.log(iterator.next()); // { value: 1, done: false }
console.log(iterator.next()); // { value: 2, done: false }
console.log(iterator.next()); // { value: 3, done: false }
console.log(iterator.next()); // { value: undefined, done: true }And also:
for (const n of numbers()) {
console.log(n); // 1, 2, 3
}Generators are convenient because you do not have to manually write return { value, done }.
Iterability across modern structures
| Structure | Iterable? | Returns |
|---|---|---|
Array | Yes | values |
String | Yes | characters |
Map | Yes | [key, value] pairs |
Set | Yes | values |
Object | No | - (can be made iterable manually via Symbol.iterator) |
arguments | Yes | argument values |
Summary
| Term | Description |
|---|---|
| Iterator | An object with a next() method that returns { value, done } |
| Iterable object | An object that has a [Symbol.iterator]() method |
Symbol.iterator | A symbol pointing to the method that creates an iterator |
| Used in | for...of, spread, Array.from, destructuring |
Generator (function*) | A simplified way to create an iterator |
Short Answer
Interview readyA concise answer to help you respond confidently on this topic during an interview.