Iterator
O Iterator é um padrão comportamental que permite percorrer uma coleção sem expor sua estrutura interna.
Imagine uma coleção:
const users = [
"João",
"Maria",
"Pedro"
];
Normalmente fazemos:
for (const user of users) {
console.log(user);
}
O Iterator permite abstrair a maneira como percorremos os elementos.
Exemplo
Criamos uma coleção:
class UserCollection {
constructor(
private users: string[]
) {}
createIterator() {
return new UserIterator(
this.users
);
}
}
Agora criamos o Iterator:
class UserIterator {
private index = 0;
constructor(
private users: string[]
) {}
hasNext() {
return (
this.index <
this.users.length
);
}
next() {
return this.users[
this.index++
];
}
}
Uso:
const collection =
new UserCollection([
"João",
"Maria",
"Pedro"
]);
const iterator =
collection.createIterator();
while (
iterator.hasNext()
) {
console.log(
iterator.next()
);
}
Resultado:
João
Maria
Pedro
O código que utiliza a coleção não precisa saber como ela armazena os dados.
Iterators nativos do JavaScript
O JavaScript já possui suporte nativo ao conceito de Iterator.
Por exemplo:
const users = [
"João",
"Maria",
"Pedro"
];
const iterator =
users[Symbol.iterator]();
console.log(
iterator.next()
);
console.log(
iterator.next()
);
Resultado:
{
value: "João",
done: false
}
E:
{
value: "Maria",
done: false
}
O for...of utiliza esse protocolo internamente.
Exemplo prático
Imagine uma aplicação que busca dados de uma API paginada.
Em vez de expor:
Página 1
Página 2
Página 3
podemos criar um Iterator que fornece os itens sequencialmente:
for await (
const user of userIterator
) {
console.log(user);
}
O consumidor não precisa saber como os dados são carregados.
Eles podem vir de:
Banco de dados
API
Paginação
Arquivo
Cache
Quando usar?
Iterator é útil quando:
- Precisamos percorrer coleções.
- Queremos esconder a estrutura interna.
- Existem diferentes formas de percorrer os dados.
- Os dados podem ser carregados sob demanda.
A ideia principal é:
Separar a forma de percorrer uma coleção da estrutura interna que armazena seus dados.