Dia 6 — Lacos de repeticao

Informatica · Conteudo · publicado em 02/10/2026
Dia 6 de 13

Lacos de repeticao

Aula 1

for, while e do...while

for, while e do...while: repetir um bloco

for repete um bloco um número controlado de vezes: inicializa o contador, testa a condição e atualiza. As três partes ficam separadas por ; dentro dos parênteses, e a ordem importa — o teste vem antes do corpo, então um limite igual ao valor inicial não entra nenhuma vez.

Em inglês essa estrutura é o loop, e o nome é o que o aluno costuma digitar na busca. O termo técnico em português é laço, e é a palavra que aparece no resto desta página.

for (let i = 0; i < 3; i++) {
  console.log('volta', i);
}
// volta 0 / volta 1 / volta 2 — e o i depois do for vale 3

O let do cabeçalho é restrito ao laço: fora dele a variável não existe (dia 2). O i++ é o que impede o laço de ser infinito; sem ele, a condição de laco nunca muda e o programa trava. O que encerra o laço é a condição de parada: o teste que deixa de ser verdadeiro.

while e do...while

while testa a condição antes de cada volta, como o for. do...while testa depois, então o corpo roda pelo menos uma vez — é a forma de pedir menu, confirmação e leitura, onde zero volta não faz sentido.

let n = 5;
while (n > 0) {
  n -= 2;              // 5, 3, 1 — para em -1
}

let tentativa = 0;
do {
  tentativa++;
} while (tentativa < 3);

O par break e continue existe nos três. break sai do laço na hora; continue pula para a próxima volta, sem rodar o que está abaixo. continue num for dispara o incremento; num while não dispara nada, e é por isso que o while com continue e sem n++ é laço infinito.

Escolher entre os três

EstruturaAssinaturaUse quando
forfor (inicio; condicao; incremento) { }você já sabe quantas vezes
for...offor (item de iteravel) { }você vai percorrer uma lista (dia 6, aula 2)
whilewhile (condicao) { }quantas vezes depende do que acontece dentro
do...whiledo { } while (condicao);o corpo tem que rodar pelo menos uma vez

O incremento não tem que ser i++. Qualquer expressão que valha um passo serve, e o i-- é a forma de contar ao contrário — o contador que não é para ser lido em ordem. O i += 2 conta de dois em dois, para os índices pares.

for (let i = 3; i > 0; i--) { }    // 3, 2, 1 — o i-- anda para tras
for (let i = 0; i < 6; i += 2) { }  // 0, 2, 4 — de dois em dois

Cada volta do laço é uma iteracao. É o termo que o material usa para o corpo inteiro do for ou do while, e o mesmo que aparece em entries() na aula 2.

Com a regra do "duas vezes ou mais, use laço", um for escrito à mão de 0 até lista.length quase sempre deveria ser for...of ou forEach. O for com índice fica quando o índice é o dado — matriz, índice menor/maior, dois laços aninhados.

Laço infinito e saída antecipada

Laço sem condição é while (true) {}; a saída vem de dentro, por break ou por return. É a forma de laço mais comum em código real, porque a condição real costuma ser "deu erro" ou "achou o que procurava", não uma contagem.

function procura(lista) {
  for (const item of lista) {
    if (item === 'alvo') {
      return 'achei na volta ' + lista.indexOf(item);
    }
  }
  return 'nao achei';
}

for (;;) é for sem nenhuma das três partes: teste nunca acontece, laço infinito. E um for que só altera a variável de teste, nunca a do incremento, também é infinito. NaN é o outro fim sem saída: i = i + 1 com i começando em NaN nunca chega em nenhuma condição, porque nenhuma comparação com NaN é verdadeira.

Exemplo

'use strict';
// Exemplo: os tres lacos de repeticao, break e continue.

// for: inicializa, testa, incrementa. O limite e exclusive.
for (let i = 0; i < 3; i++) {
  console.log('for:', i);
}

// O let do cabecalho nao existe depois do for.
console.log('i nao existe aqui:', typeof i);

// while: a condicao e testada ANTES de cada volta.
let n = 5;
while (n > 0) {
  n -= 2;
  console.log('while:', n);
}

// do...while: testa DEPOIS, entao o corpo roda pelo menos uma vez.
let tentativa = 0;
do {
  tentativa++;
  console.log('do...while: tentativa', tentativa);
} while (tentativa < 3);

// Incremento maior que 1 nao precisa de for: while resolve.
let linha = 0;
while (linha < 6) {
  linha += 2;
}
console.log('linhas pares de 0 a 5:', linha);

// break sai do laco na hora.
let somatorio = 0;
for (const numero of [4, 8, 15, 16, 23, 42]) {
  if (numero > 20) {
    console.log('break no numero', numero, '| acumulado ate aqui:', somatorio);
    break;
  }
  somatorio += numero;
}
console.log('somatorio final:', somatorio);

// continue pula o resto do corpo e vai para a proxima volta.
console.log('--- so os numeros impares ---');
for (let i = 1; i <= 10; i++) {
  if (i % 2 === 0) {
    continue;
  }
  console.log(i);
}

// continue dentro de um for ainda dispara o incremento do cabecalho.
console.log('--- i no continue ---');
for (let i = 0; i < 3; i++) {
  if (i === 1) {
    continue;
  }
  console.log('i =', i);
}

// Return antecipado: sai da funcao, nao so do laco.
function somaAte(lista, limite) {
  let total = 0;
  for (const valor of lista) {
    if (valor > limite) {
      return total;
    }
    total += valor;
  }
  return total;
}
console.log('somaAte([1,2,3,4,5], 3) =', somaAte([1, 2, 3, 4, 5], 3));

// while (true): a condicao real costuma ser "deu erro" ou "achou".
function validade(opcoes) {
  let i = 0;
  while (true) {
    if (i >= opcoes.length) {
      return 'opcao invalida';
    }
    if (opcoes[i] === 'sim') {
      return 'confirmado na opcao ' + i;
    }
    i++;
  }
}
console.log(validade(['nao', 'talvez', 'sim']), '|', validade(['nao', 'nao']));

// while com continue e sem incremento e laco infinito: e por isso que
// o for e mais seguro quando o continue fica no corpo.
let seguro = 0;
for (let i = 0; i < 3; i++) {
  if (i === 0) {
    continue;
  }
  seguro += 1;
}
console.log('o for disparou o incremento mesmo com continue:', seguro);

Saída real

for: 0
for: 1
for: 2
i nao existe aqui: undefined
while: 3
while: 1
while: -1
do...while: tentativa 1
do...while: tentativa 2
do...while: tentativa 3
linhas pares de 0 a 5: 6
break no numero 23 | acumulado ate aqui: 43
somatorio final: 43
--- so os numeros impares ---
1
3
5
7
9
--- i no continue ---
i = 0
i = 2
somaAte([1,2,3,4,5], 3) = 6
confirmado na opcao 2 | opcao invalida
o for disparou o incremento mesmo com continue: 2
Aula 2

for...of e for...in: percorrer colecoes

Percorrer lista: for...of e for...in

for...of percorre os valores. for...in percorre as chaves. É a diferença inteira, e escolher o errado é a causa número um de bug em laço: for...in num array devolve os índices em forma de texto, e o código continua rodando sem erro nenhum.

const frutas = ['maçã', 'banana', 'uva'];

for (const fruta of frutas) {          // valores: 'maçã', 'banana', 'uva'
  console.log(fruta);
}

for (const indice in frutas) {         // chaves: '0', '1', '2' (texto)
  console.log(indice, frutas[indice]);
}

Regra prática: for...in é para objeto, e objeto é dia 9. Num array, use for...of.

É o for...of que percorre array: cada volta entrega um elemento, na ordem em que ele está, sem passar índice. Percorrer array é, no fundo, o que o map e o filter fazem por baixo — o for...of entrega o elemento, o método decide o que fazer com ele.

O que dá para percorrer

for...of aceita qualquer iterável: array, string (cada caractere, um por vez), Set, Map (cada par [chave, valor]), NodeList do DOM e o arguments implícito. for...in aceita qualquer objeto com propriedades enumeráveis, inclusive um array.

FormaAssinaturaEntrega
for...offor (const item of iteravel) { }o valor de cada elemento
for...infor (const chave in objeto) { }o nome da chave, sempre texto
entries()iteravel.entries()pares [indice, valor], para for...of
keys()iteravel.keys()só os índices, para for...of
values()iteravel.values()só os valores, é o padrão do for...of

Quem precisa do índice e do valor usa entries(): for (const [i, valor] of lista.entries()). A desestruturação vem no dia 9; por enquanto o par também funciona com par[0] e par[1].

Percorrer string e quebrando no meio

O for...of sobre texto devolve caracteres, com acento e emoji contados como um só:

for (const letra of 'Sala 12 -ção') { }

break e continue valem igual dentro dos dois. O break dentro do laço encerra o laço inteiro, na hora, e o que está abaixo dele não roda; o continue no laço pula para a próxima volta, deixando o resto do corpo para trás. Um for dentro de outro com break só sai o de dentro — para sair os dois de uma vez, o return resolve.

Quando o for...of não serve

for...of não dá índice numérico para usar como posição. lista.indexOf('uva') devolve 2; o i do for...of não existe, e o indice do for...in é '2', texto — com ele, lista[indice] funciona, mas indice + 1 concatena em vez de somar.

Nos três casos abaixo, volte para o for com índice:

  1. Precisa do índice para calcular, não só para exibir.
  2. Precisa andar em duas listas ao mesmo tempo no mesmo índice.
  3. A lista muda de tamanho dentro do laço e o fim deve ser fixado no começo:
for (let i = 0; i < lista.length; i++) { }

Percorrer o resultado de um filter com for...in devolve os índices originais do array, não os do array novo — é por isso que o map sobre um for...in embaralha a posição. E um for...of sobre uma string quebra o texto em caracteres, nunca em palavras: para isso é split(' ') (dia 4).

Exemplo

'use strict';
// Exemplo: for...of percorre valores, for...in percorre chaves.

const frutas = ['maçã', 'banana', 'uva'];

// for...of entrega cada valor, na ordem.
console.log('--- for...of (valores) ---');
for (const fruta of frutas) {
  console.log(fruta);
}

// for...in entrega o NOME da chave. Em array, a chave e o indice em texto.
console.log('--- for...in (chaves) ---');
for (const indice in frutas) {
  console.log(JSON.stringify(indice), '->', frutas[indice], '| typeof', typeof indice);
}

// A prova do bug: indice e texto, entao a conta vira concatenacao.
for (const indice in frutas) {
  console.log('indice + 1 =', indice + 1, '(texto); Number(indice) + 1 =', Number(indice) + 1);
}

// for...of nao tem indice. Quem precisa dele usa entries().
console.log('--- for...of com entries() ---');
for (const [indice, valor] of frutas.entries()) {
  console.log(indice, valor);
}

// string e iteravel: um caractere por volta, acento junto.
console.log('--- string ---');
for (const caractere of 'ação') {
  console.log(caractere, '-', caractere.length, 'unidade de codigo');
}

// Set nao repete valor: percorrer duas vezes a mesma chave nao acontece.
const idiomas = new Set(['pt', 'en', 'pt', 'es']);
console.log('--- Set, sem repeticao ---');
for (const idioma of idiomas) {
  console.log(idioma);
}

// Map entrega o par [chave, valor] no for...of.
const estoque = new Map([['arroz', 3], ['feijão', 7]]);
console.log('--- Map ---');
for (const [produto, quantidade] of estoque) {
  console.log(produto, '=', quantidade);
}

// break e continue funcionam igual nos dois.
console.log('--- break ---');
for (const fruta of frutas) {
  if (fruta === 'uva') {
    break;
  }
  console.log('ate parar:', fruta);
}

console.log('--- continue ---');
for (const fruta of frutas) {
  if (fruta === 'banana') {
    continue;
  }
  console.log('passei:', fruta);
}

// Percorrer uma lista de objetos, que e o caso real de uso.
const pedidos = [
  { id: 1, cliente: 'Ana' },
  { id: 2, cliente: 'Bia' },
  { id: 3, cliente: 'Cau' },
];
console.log('--- pedidos ---');
for (const pedido of pedidos) {
  console.log(pedido.id, pedido.cliente);
}

// Duas listas andando juntas: precisa de indice numerico.
const nomes = ['Ana', 'Bia', 'Cau'];
const notas = [8, 9, 7];
console.log('--- duas listas no mesmo indice ---');
for (let i = 0; i < nomes.length; i++) {
  console.log(nomes[i], '=', notas[i]);
}

// for...of tambem funciona em qualquer objeto com Symbol.iterator.
// E por isso que NodeList, Set e Map respondem ao for...of sem adapter.
const Iteravel = {
  itens: [10, 20],
  *[Symbol.iterator]() {
    yield* this.itens;
  },
};
console.log('--- objeto com Symbol.iterator ---');
let total = 0;
for (const item of Iteravel) {
  total += item;
}
console.log('soma do iteravel:', total);

Saída real

--- for...of (valores) ---
maçã
banana
uva
--- for...in (chaves) ---
"0" -> maçã | typeof string
"1" -> banana | typeof string
"2" -> uva | typeof string
indice + 1 = 01 (texto); Number(indice) + 1 = 1
indice + 1 = 11 (texto); Number(indice) + 1 = 2
indice + 1 = 21 (texto); Number(indice) + 1 = 3
--- for...of com entries() ---
0 maçã
1 banana
2 uva
--- string ---
a - 1 unidade de codigo
ç - 1 unidade de codigo
ã - 1 unidade de codigo
o - 1 unidade de codigo
--- Set, sem repeticao ---
pt
en
es
--- Map ---
arroz = 3
feijão = 7
--- break ---
ate parar: maçã
ate parar: banana
--- continue ---
passei: maçã
passei: uva
--- pedidos ---
1 Ana
2 Bia
3 Cau
--- duas listas no mesmo indice ---
Ana = 8
Bia = 9
Cau = 7
--- objeto com Symbol.iterator ---
soma do iteravel: 30