W3docs

Iteráveis e Iteradores em JavaScript

Entenda iteráveis em JavaScript: protocolo de iteração, iteradores personalizados, generators, sequências infinitas e consumo com for...of.

Introdução aos Iteráveis em JavaScript

Iteráveis em JavaScript são objetos que implementam um protocolo específico, permitindo que sejam consumidos por construções de iteração como for...of. Este guia aborda os conceitos fundamentais, os iteráveis embutidos e técnicas práticas para trabalhar com coleções.

O que são Iteráveis em JavaScript?

Em essência, um iterável é um objeto que implementa o método Symbol.iterator, possibilitando o acesso sequencial aos seus elementos. Vários tipos embutidos em JavaScript são iteráveis, incluindo Array, String, Map, Set e outros. É importante distinguir entre um iterável (o objeto sendo percorrido) e um iterador (o objeto retornado por Symbol.iterator que realiza a travessia). Esses iteráveis são fundamentais para diversas operações, como laços e manipulação de dados.

Informação

Para uma exploração detalhada dos objetos Map e Set em JavaScript, consulte nosso guia completo sobre JavaScript Map e Set.

Exemplo de um Iterável: Array

Veja um exemplo básico de um iterável em JavaScript:

javascript— editable

Este trecho de código demonstra a iteração sobre um array de frutas, um iterável comum. O laço for...of chama automaticamente o método Symbol.iterator do iterável e consome o iterador resultante até que done seja true. Veja Laços em JavaScript para conhecer toda a família de construções de iteração.

Aviso

Não confunda for...of com for...in. O for...of itera sobre os valores produzidos por um iterável (itens de array, caracteres de string, entradas de Map). O for...in itera sobre as chaves de propriedade enumeráveis de um object — incluindo as herdadas — e é destinado a objetos simples, não arrays. Usar for...in em um array fornece strings de índice ("0", "1", …) e pode capturar propriedades extras, portanto prefira for...of para dados ordenados.

O Protocolo do Iterador

A base de um iterável é seu método Symbol.iterator. O protocolo é um contrato preciso:

  1. Um iterável possui um método identificado por Symbol.iterator. Ao chamá-lo, retorna um iterador.
  2. Um iterador é um object com um método next().
  3. Cada chamada a next() retorna um object { value, done }:
    • done: falsevalue é o próximo item da sequência.
    • done: true — a iteração terminou (value é ignorado ou carrega um resultado final opcional).

Qualquer object que siga este contrato funciona com for...of, o operador spread, desestruturação e Array.from() — mesmo que você mesmo tenha escrito o object. Symbol é uma chave única embutida; veja Tipo Symbol para entender por que os métodos de protocolo usam um em vez de um nome de string comum.

Exemplo: Um iterável range personalizado

Um caso de uso clássico é um object que produz um intervalo numérico de forma lazy, sem nunca construir um array:

javascript— editable

Neste exemplo, o método [Symbol.iterator]() retorna um iterador novo a cada chamada, de modo que o mesmo object range pode ser percorrido mais de uma vez. A sintaxe de método abreviada garante que this se refira corretamente ao object range. (Usar uma arrow function para [Symbol.iterator] capturaria this de forma léxica e quebraria o padrão.)

Generators: a forma fácil de criar iteráveis

Escrever next() e controlar o estado manualmente é verboso. Uma função generator — declarada com function* e usando yield — produz um iterador automaticamente. Cada yield pausa a função e entrega um valor ao consumidor; a execução é retomada na próxima chamada a next(). O mesmo range fica bem mais conciso:

javascript— editable

O * antes do nome do método o torna um método generator, portanto range é iterável com quase nenhum código boilerplate. Para tudo que os generators podem fazer — incluindo comunicação bidirecional e delegação com yield* — veja Generators e Iteradores e generators assíncronos.

Sequências infinitas e lazy

Como um iterador só calcula o próximo valor quando solicitado, ele pode descrever sequências grandes demais — ou mesmo infinitas — para caber na memória. Esse é o principal motivo para escrever um iterador personalizado em vez de usar um array:

javascript— editable
Aviso

Nunca use spread ([...naturals()]) ou for...of sem um break em um iterável infinito — ele entrará em loop para sempre. Em vez disso, obtenha um número finito de valores com next().

Consumindo Iteráveis

Uma vez que um object é iterável, toda a linguagem se abre para ele: qualquer construção que aceita um iterável funciona com seu tipo personalizado da mesma forma que funciona com arrays.

Usando Array.from()

O método Array.from() cria um novo array a partir de qualquer object iterável (ou semelhante a um array). Ele também aceita uma função de mapeamento opcional como segundo argumento, aplicada a cada elemento durante a construção do array — mais prático do que Array.from(it).map(fn) porque evita uma segunda passagem:

javascript— editable

Veja JavaScript Map e Set para mais detalhes sobre Set, e Métodos de Array para o que fazer depois de ter um array.

Sintaxe Spread com Iteráveis

A sintaxe spread (...) expande um iterável onde argumentos ou elementos são esperados — mesclando arrays, copiando ou passando itens como argumentos de função:

javascript— editable

Para uma visão completa de ... tanto em posição de spread quanto de coleta, veja Parâmetros rest e sintaxe spread.

Desestruturação e rest

A atribuição por desestruturação extrai valores de qualquer iterável por posição, e o padrão rest (...) reúne o restante em um array:

javascript— editable

Saiba mais em Atribuição por desestruturação.

O iterável String e segurança Unicode

Strings são iteráveis, e o importante é que o iterador percorre pontos de código Unicode, não unidades de código de 16 bits. Isso significa que caracteres de par substituto (emoji, alguns scripts) são mantidos inteiros — ao contrário de indexação com [i] ou laços for antigos sobre .length, que podem dividi-los:

javascript— editable

Sempre que precisar contar ou dividir caracteres visíveis ao usuário corretamente, itere a string (ou use spread) em vez de depender de .length. Veja o capítulo Strings para mais detalhes.

Resumo

  • Um object é iterável quando possui um método [Symbol.iterator]() que retorna um iterador — um object cujo next() produz { value, done }.
  • Prefira um generator (function* / yield) a escrever next() manualmente; é a forma mais curta e menos propensa a erros de tornar algo iterável.
  • Use for...of para os valores de dados ordenados/iteráveis; use for...in apenas para as chaves de objetos simples.
  • Uma vez iterável, seu tipo se conecta a spread, desestruturação, rest, Array.from(it, mapFn) e muitas APIs embutidas gratuitamente.
  • Iteradores são lazy, portanto podem modelar sequências infinitas ou enormes que um array jamais poderia.
  • Itere strings (não as indexe) para tratar caracteres Unicode como emoji com segurança.

Prática

Prática
Quais das afirmações a seguir sobre iteráveis em JavaScript são corretas?
Quais das afirmações a seguir sobre iteráveis em JavaScript são corretas?
Was this page helpful?