Що таке ітератор?
Що таке ітератор
Ітератор (iterator) - це об'єкт, який по черзі повертає елементи якоїсь послідовності при кожному виклику методу .next().
Формальне визначення:
Ітератор - це об'єкт, що реалізує метод
next(), який повертає об'єкт вигляду{ value: any, done: boolean }
Як виглядає ітератор вручну
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 }Коли done: true, ітерація завершується.
Що робить ітератор усередині for...of
Коли ти пишеш:
for (const item of ['a', 'b', 'c']) {
console.log(item);
}Під капотом JavaScript робить приблизно таке:
const iterable = ['a', 'b', 'c'];
const iterator = iterable[Symbol.iterator](); // створює ітератор
while (true) {
const { value, done } = iterator.next();
if (done) break;
console.log(value);
}Що таке ітерований об'єкт (iterable)
Об'єкт є ітерованим, якщо в нього є метод:
obj[Symbol.iterator]()який повертає ітератор.
Приклади вбудованих ітерованих структур:
ArrayStringMapSetargumentsNodeList(у браузері)TypedArray
Приклад: власний ітерований об'єкт
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
}Коли JS зустрічає for...of, він викликає range[Symbol.iterator]() і використовує повернений ітератор.
Приклад: рядок - теж ітерований
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 }Ітератори + Spread / Destructuring / Array.from
Усі ці конструкції всередині використовують ітератор:
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 2Що робить Symbol.iterator
Symbol.iterator - це спеціальний символ, що визначає "ітерованість" об'єкта. JS викликає цей метод автоматично, коли потрібно перебрати об'єкт (for...of, spread тощо).
Генератори = автоматичні ітератори
Генератор (function*) - це функція, яка сама створює ітератор.
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 }А також:
for (const n of numbers()) {
console.log(n); // 1, 2, 3
}Генератори зручні, бо тобі не потрібно вручну писати return { value, done }.
Ітерованість у сучасних структурах
| Структура | Ітерована? | Повертає |
|---|---|---|
Array | Так | значення |
String | Так | символи |
Map | Так | пари [key, value] |
Set | Так | значення |
Object | Ні | - (можна зробити вручну через Symbol.iterator) |
arguments | Так | значення аргументів |
Підсумок
| Термін | Опис |
|---|---|
| Ітератор | Об'єкт з методом next(), що повертає { value, done } |
| Ітерований об'єкт | Об'єкт, у якого є метод [Symbol.iterator]() |
Symbol.iterator | Символ, що вказує на метод, який створює ітератор |
| Використовується в | for...of, spread, Array.from, деструктуризація |
Генератор (function*) | Спрощений спосіб створити ітератор |
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.