Loops: for, while, do while, for...of e for...in

1. Introdução aos Loops em JavaScript

Loops são estruturas fundamentais que permitem executar um bloco de código repetidamente enquanto uma condição específica for verdadeira. Em JavaScript, existem cinco tipos principais de loops: for, while, do...while, for...of e for...in. Cada um possui características únicas que os tornam mais adequados para diferentes cenários.

No ecossistema JavaScript moderno, os loops são essenciais tanto no back-end com Node.js quanto no front-end com React. No Node.js, loops são utilizados para processar streams de dados, gerenciar filas de tarefas e iterar sobre grandes conjuntos de informações. No React, loops são a base para renderizar listas de componentes dinamicamente, como exibir itens de um carrinho de compras ou listar posts de um blog.

A escolha do loop correto impacta diretamente a legibilidade, performance e manutenibilidade do código. Vamos explorar cada tipo detalhadamente.

2. Loop for clássico

O loop for clássico é o mais tradicional e oferece controle granular sobre a iteração. Sua sintaxe é composta por três expressões: inicialização, condição e incremento.

// Sintaxe básica
for (let i = 0; i < 5; i++) {
    console.log(`Iteração número ${i + 1}`);
}

// Exemplo prático no Node.js: processando dados de um array
const usuarios = [
    { nome: 'Ana', ativo: true },
    { nome: 'Carlos', ativo: false },
    { nome: 'Maria', ativo: true }
];

for (let i = 0; i < usuarios.length; i++) {
    if (usuarios[i].ativo) {
        console.log(`${usuarios[i].nome} está ativo`);
    }
}

Este loop é ideal quando você precisa de controle sobre o índice e deseja modificar a lógica de iteração manualmente, como pular elementos ou percorrer em ordem inversa.

3. Loop while

O loop while executa um bloco de código enquanto uma condição especificada for verdadeira. É particularmente útil quando o número de iterações não é conhecido antecipadamente.

// Sintaxe básica
let contador = 0;
while (contador < 3) {
    console.log(`Contador: ${contador}`);
    contador++;
}

// Exemplo no Node.js: leitura de arquivo linha por linha
const fs = require('fs');
const linhas = fs.readFileSync('dados.txt', 'utf8').split('\n');
let indice = 0;

while (indice < linhas.length) {
    const linha = linhas[indice].trim();
    if (linha) {
        console.log(`Processando: ${linha}`);
    }
    indice++;
}

O while é excelente para cenários onde a condição de parada depende de fatores externos, como disponibilidade de dados em uma stream ou resposta de uma API.

4. Loop do...while

O do...while garante que o bloco de código seja executado pelo menos uma vez, pois a condição é verificada após a execução.

// Sintaxe básica
let tentativas = 0;
do {
    console.log(`Tentativa ${tentativas + 1}`);
    tentativas++;
} while (tentativas < 3);

// Caso de uso: retry de operação no Node.js
function conectarBanco() {
    let tentativa = 0;
    let conectado = false;

    do {
        tentativa++;
        console.log(`Tentando conectar... (tentativa ${tentativa})`);
        conectado = Math.random() > 0.7; // Simulação de conexão

        if (conectado) {
            console.log('Conexão estabelecida!');
        } else if (tentativa >= 3) {
            console.log('Falha após 3 tentativas');
        }
    } while (!conectado && tentativa < 3);

    return conectado;
}

Este loop é perfeito para validações de entrada do usuário, onde você precisa executar a ação ao menos uma vez antes de verificar a condição.

5. Loop for...of

O for...of itera sobre valores de objetos iteráveis, como arrays, strings, Map e Set. Sua sintaxe simplificada melhora a legibilidade do código.

// Iterando sobre array
const frutas = ['maçã', 'banana', 'laranja'];
for (const fruta of frutas) {
    console.log(fruta);
}

// Exemplo em React: renderizando lista de componentes
function ListaTarefas({ tarefas }) {
    return (
        <ul>
            {tarefas.map((tarefa, index) => (
                <li key={index}>{tarefa.titulo}</li>
            ))}
        </ul>
    );
}

// Mas também podemos usar for...of para processar dados antes de renderizar
function ProcessadorTarefas({ tarefas }) {
    const tarefasAtivas = [];
    for (const tarefa of tarefas) {
        if (tarefa.status === 'pendente') {
            tarefasAtivas.push(tarefa);
        }
    }

    return (
        <div>
            {tarefasAtivas.map(tarefa => (
                <p key={tarefa.id}>{tarefa.descricao}</p>
            ))}
        </div>
    );
}

No React, embora map() seja mais comum para renderização, o for...of é útil para pré-processar dados antes de passá-los aos componentes.

6. Loop for...in

O for...in itera sobre propriedades enumeráveis de objetos, incluindo aquelas herdadas do protótipo. É importante não usá-lo para arrays, pois ele itera sobre índices como strings e pode incluir propriedades não numéricas.

// Iterando sobre propriedades de objeto
const usuario = {
    nome: 'João',
    idade: 30,
    email: 'joao@email.com'
};

for (const propriedade in usuario) {
    if (usuario.hasOwnProperty(propriedade)) {
        console.log(`${propriedade}: ${usuario[propriedade]}`);
    }
}

// ❌ Evite usar for...in em arrays
const numeros = [10, 20, 30];
for (const indice in numeros) {
    console.log(typeof indice); // "string", não "number"!
    console.log(numeros[indice]);
}

// ✅ Use for...of para arrays
for (const numero of numeros) {
    console.log(numero); // 10, 20, 30
}

A diferença crucial: for...in retorna chaves (propriedades), enquanto for...of retorna valores.

7. Boas Práticas e Performance

Ao escolher um loop, considere:

  • for clássico: Quando precisa de controle sobre índice e incremento
  • while: Para iterações com condição de parada variável
  • do...while: Quando precisa garantir pelo menos uma execução
  • for...of: Para iterar sobre valores de coleções (preferido para arrays)
  • for...in: Apenas para objetos, com verificação de hasOwnProperty

Performance e boas práticas:

// Evite loops aninhados pesados
// ❌ Ruim: O(n²)
for (let i = 0; i < array1.length; i++) {
    for (let j = 0; j < array2.length; j++) {
        // processamento pesado
    }
}

// ✅ Bom: Use Map para lookup O(1)
const mapa = new Map();
for (const item of array2) {
    mapa.set(item.id, item);
}

// Use break e continue com moderação
for (const item of dados) {
    if (item.tipo === 'ignorar') continue;
    if (item.tipo === 'parar') break;
    processar(item);
}

// Em React, prefira métodos funcionais para imutabilidade
function ListaUsuarios({ usuarios }) {
    return (
        <ul>
            {usuarios
                .filter(u => u.ativo)
                .map(u => (
                    <li key={u.id}>{u.nome}</li>
                ))}
        </ul>
    );
}

8. Erros Comuns e Debug

Os erros mais frequentes com loops incluem:

// 1. Loop infinito
let i = 0;
while (i < 10) {
    console.log('Infinito!');
    // Esqueceu de incrementar i
}

// 2. Modificação do array durante iteração
const arr = [1, 2, 3, 4, 5];
for (let i = 0; i < arr.length; i++) {
    if (arr[i] % 2 === 0) {
        arr.splice(i, 1); // Modifica o array enquanto itera
    }
}

// 3. Problema de escopo com var
for (var j = 0; j < 3; j++) {
    setTimeout(() => console.log(j), 100); // Imprime 3, 3, 3
}

// ✅ Solução: usar let
for (let k = 0; k < 3; k++) {
    setTimeout(() => console.log(k), 100); // Imprime 0, 1, 2
}

Para debug, utilize console.log estratégico dentro dos loops ou ferramentas como Node.js Debugger e React DevTools para inspecionar o estado durante iterações.


Dominar os diferentes tipos de loops em JavaScript é essencial para escrever código eficiente e legível, tanto no Node.js quanto no React. Cada loop tem seu propósito específico, e a escolha correta depende do contexto e dos requisitos do seu projeto.

Referências