Repetir com controle, não no escuro
Loops executam blocos repetidamente — sobre coleções, até condição ou intervalo numérico. Processamento em lote (relatórios, importações, filas) depende de repetição correta e previsível.
for...of em coleções materializadas
const faturas = [
{ cliente: 'A', valor: 1200 },
{ cliente: 'B', valor: 890 },
{ cliente: 'C', valor: 2100 }
];
let total = 0;
for (const fatura of faturas) {
total += fatura.valor;
}
for clássico quando índice importa
for (let i = 0; i < linhas.length; i++) {
if (i % 2 === 0) {
linhas[i] = linhas[i].trim();
}
}
Off-by-one: i < length vs i <= length — erro clássico. Trace com três elementos manualmente.
while e paginação
async function buscarTodasPaginas(fetchPagina, paginaInicial = 1) {
let pagina = paginaInicial;
const acumulado = [];
while (true) {
const { itens, temProxima } = await fetchPagina(pagina);
acumulado.push(...itens);
if (!temProxima) break;
pagina += 1;
}
return acumulado;
}
map, filter, reduce
const funcionarios = [
{ nome: 'Rita', dept: 'TI', salario: 8000 },
{ nome: 'Paulo', dept: 'RH', salario: 6500 },
{ nome: 'Lia', dept: 'TI', salario: 9200 }
];
const folhaTi = funcionarios
.filter(f => f.dept === 'TI')
.map(f => ({ ...f, bonus: f.salario * 0.10 }))
.reduce((acc, f) => acc + f.salario + f.bonus, 0);
break, continue e legibilidade
break interrompe loop; continue pula iteração. Uso excessivo indica loop candidato a refatoração (extrair função ou usar filter).
Performance consciente
- Evite await dentro de loop grande sem controle de concorrência — pode saturar API.
- Para milhões de registros, processamento streaming ou batch, não array gigante em memória.
- Meça antes de otimizar; loops claros vencem micro-otimização prematura.
Estudo de caso: conciliação bancária simplificada
Dado extrato com centenas de lançamentos, marque duplicatas por hash de (data + valor + descrição normalizada):
function normalizarDescricao(texto) {
return texto.trim().toUpperCase().replace(/\s+/g, ' ');
}
function encontrarDuplicatas(lancamentos) {
const vistos = new Map();
const duplicatas = [];
for (const item of lancamentos) {
const chave = `${item.data}|${item.valor}|${normalizarDescricao(item.descricao)}`;
if (vistos.has(chave)) {
duplicatas.push({ original: vistos.get(chave), duplicata: item });
} else {
vistos.set(chave, item);
}
}
return duplicatas;
}
Este padrão combina loop, transformação de string e estrutura Map — três conceitos das semanas anteriores.
Quando evitar loop manual
Se a operação já existe na biblioteca padrão (ex.: Array.prototype.some, every, find), prefira expressividade. Loops manuais ficam para acumulações customizadas ou controle fino de fluxo.
Loops aninhados e complexidade
Dois loops aninhados sobre coleções de tamanho n e m tendem a O(n×m) operações. Para 1.000 × 1.000 itens, são um milhão de iterações — aceitável em script local, problemático em API síncrona. Antes de aninhar, pergunte: dá para indexar uma coleção em Map e reduzir a um loop?
// O(n×m) — evite em listas grandes
function paresNaive(a, b) {
const resultado = [];
for (const x of a) {
for (const y of b) {
if (x.id === y.id) resultado.push({ x, y });
}
}
return resultado;
}
// O(n + m) — indexe primeiro
function paresComMap(a, b) {
const indice = new Map(a.map(item => [item.id, item]));
return b
.filter(y => indice.has(y.id))
.map(y => ({ x: indice.get(y.id), y }));
}
Esta refatoração aparece em entrevistas júnior/pleno: não é micro-otimização, é legibilidade + escala previsível.
Armadilhas comuns em while
- Loop infinito: condição nunca muda — sempre defina variável de saída e incremento explícitos.
- Mutar coleção durante iteração: remover item de array enquanto percorre com
for...ofpode pular elementos; filtre para novo array ou itere de trás para frente. - await em série desnecessário: buscar 50 URLs uma a uma é lento; batch com limite de concorrência quando a API permitir.
Exercício guiado: relatório de vendas por região
Implemente em três etapas, sem pular validação:
- Receba array de vendas
{ regiao, valor, data }. - Filtre vendas do trimestre atual (compare mês/ano com
Date). - Agrupe por região com
reducee calcule total e ticket médio.
function relatorioTrimestre(vendas, ano, trimestre) {
const mesInicio = (trimestre - 1) * 3;
const mesFim = mesInicio + 2;
const noPeriodo = vendas.filter(v => {
const d = new Date(v.data);
return d.getFullYear() === ano
&& d.getMonth() >= mesInicio
&& d.getMonth() <= mesFim;
});
return noPeriodo.reduce((acc, v) => {
if (!acc[v.regiao]) {
acc[v.regiao] = { total: 0, quantidade: 0 };
}
acc[v.regiao].total += v.valor;
acc[v.regiao].quantidade += 1;
return acc;
}, {});
}
Teste com array vazio, uma região só, e venda na fronteira do trimestre (31/03 vs 01/04). Documente resultado esperado no seu README pessoal.
Do loop imperativo ao estilo declarativo
Em código de equipe, filter → map → reduce comunica intenção. Em hot path com milhões de registros, um for único pode ser mais eficiente — mas só após medir. Na fase de aprendizado, priorize clareza; o runtime moderno perdoa loops pequenos em scripts de estudo.
Conexão com a semana seguinte
Quando um loop não termina ou o total sai errado, você precisa ler erros e inspecionar variáveis — tema do próximo post. Antes de pedir ajuda externa, trace manualmente três iterações com lápis e papel: valor de i, item atual, acumulador.
Para aprofundar na web
Para entender melhor este tema, pesquise por:
- "for loop while for...of JavaScript MDN" — quando usar cada tipo de repetição
- "array map filter reduce explicado" — estilo declarativo sobre coleções
- "off by one error loop programação" — erro clássico de limite < vs <=
- "Big O notation introdução iniciante" — intuição sobre loops aninhados
- "Map JavaScript estrutura chave valor" — indexação O(1) para lookups frequentes
Refaça o exercício de relatório por região usando apenas reduce — compare com loop for.
Atividades
Off-by-one típico ocorre quando:
Ver resposta
Resposta correta: B) Confunde i < n com i <= n
Limite inclusivo vs exclusivo altera quantidade de iterações em um.
filter + reduce comunicam melhor:
Ver resposta
Resposta correta: A) Intenção de transformar e agregar coleções
Estilo declarativo deixa explícito filtrar subset e reduzir a um valor.
Quando preferir while em vez de for...of?
Ver resposta
Quando número de iterações não é conhecido antecipadamente: paginação até esgotar, leitura de stream, aguardar condição externa.
0 comments