Dia 6 — Laços de repetição

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

Laços de repetição

Aula 1

for e forEach

for e forEach

Repetição é o que o laço faz: um laço repete um bloco de código. O for sem chaves sofre do mesmo defeito do if sem chaves: o for é o laço com

contador, e o bloco do laço é o que repete. Três partes separadas por ponto e vírgula — a variável do laço com o valor

inicial, a condição que precisa continuar verdadeira, e o passo.

for (let i = 0; i < 3; i++) {
  console.log(i);
}

Cada iteração é uma volta. O JavaScript confere a condição antes de cada

volta, e sai quando ela falha — o i < 3 produz 0, 1, 2, e no i igual a

3 o laço termina. É por isso que o < fica e não o <=: com <= seriam quatro

voltas.

O passo não precisa ser i++. i += 2 pula de dois em dois, e i-- desce:

for (let i = 2; i <= 8; i += 2) { console.log(i); }   // 2, 4, 6, 8

O exemplo imprime as três voltas (i = 0, i = 1, i = 2) e logo depois tenta

usar o i fora do laço, num try/catch que devolve

depois do laco: ReferenceError - i is not defined. Não é coincidência: o let

do for cria um nome que pertence só ao laço, e por isso ele desaparece no fim.

Um var no lugar do let sobreviveria, que é o vazamento de escopo da aula de

let e const aparecendo aqui de novo.

O lado do <= está duas linhas abaixo, e o console imprime volta 0, volta 1

e volta 2 — três linhas, e não quatro. A conta é a mesma: 0 <= 2, 1 <= 2 e

2 <= 2 passam, e 3 <= 2 falha.

O passo aparece em duas sequências: de dois em dois: 2, 4, 6, 8 — quatro

voltas porque o <= aqui é o do exemplo, e descendo: 3, 2, 1 — três voltas

com i--, encerrando em 1 porque a condição i > 0 falha nele.

forEach: a volta que já sabe o tamanho

forEach é o método do array que executa uma função uma vez para cada item. Não

tem contador, não tem condição e não tem passo — o array é o que controla o

número de voltas:

const tarefas = ['estudar', 'treinar'];
tarefas.forEach((tarefa, indice) => {
  console.log(indice, tarefa);
});

A função passada para o forEach recebe três argumentos: o item, o índice

e o array inteiro. Cada volta cria um escopo próprio, então declarar const dentro

do laço é seguro e o nome não vaza para fora.

forEach não devolve nada. É o detalhe que faz ele ser preterido em favor do

map quando o resultado importa: o forEach serve para efeito colateral —

registrar, contar, chamar função — e o map serve para produzir um array novo.

O exemplo passa a lista de três tarefas pelo forEach e imprime três linhas com

o índice antes do texto: forEach: 0 estudar, forEach: 1 treinar, `forEach: 2

descansar. Três voltas porque o array tem três itens — o forEach` não tem

condição para consultar, e é isso que o difere do for.

A linha do retorno é a prova de que ele não devolve nada:

retorno do forEach: undefined. A função passada devolvia t.length, o tamanho

cada texto, e o resultado da chamada inteira foi undefined. Com o map, o

mesmo t.length teria produzido [7, 7, 9] — um array com o tamanho de cada

item. A escolha entre os dois é sempre a mesma: se o resultado volta para a

tela, é map; se só o registro importa, é forEach.

E o exemplo mostra o uso que o material chama de efeito colateral:

tarefas.forEach(() => { total = total + 1; }) termina em

quantas tarefas: 3. A seta não devolve nada e ninguém espera que devolva; o que

ela faz é mexer no total de fora, uma volta por item. É o forEach na função

de contar, que é metade dos casos em que ele é a escolha certa.

break e continue dentro do laço

break sai do laço inteiro. continue pula para a próxima volta, deixando o resto

do bloco de fora:

for (const n of [1, 2, 3, 4, 5]) {
  if (n === 3) break;      // para tudo
  console.log(n);          // imprime 1 e 2
}

A combinação que aparece em tela é continue com filtro: pular o item que não

interessa e seguir com o resto, sem aninhar o código em if dentro de if.

O exemplo mostra os dois em laços separados. Com break, saem duas linhas —

com break: 1 e com break: 2 — e o 3 nunca aparece, porque é ele que

dispara a saída. Com continue em n % 2 === 0, saem três:

com continue (impares): 1, 3 e 5. Os pares 2 e 4 foram pulados sem

imprimir, e o laço seguiu até o fim.

O laço vazio — laço sem corpo, só ponto e vírgula — é código válido e bug:

o for roda o número de vezes pedido sem executar nada, e i++ some. Aparece

quando alguém deixa a chave de um bloco vazio de lado.

O detalhe do forEach que costuma ser lembrado na hora errada: o break não

sai dele para a lista inteira. Ele sai do laço interno da função que o

forEach chama, e o forEach continua com o próximo item. Para parar a lista

inteira de verdade, é for...of com break — assunto da aula seguinte.

A ordem do laço com break dentro de função

Um break dentro de uma função não sai do for que está chamando a função:

ele sai do laço mais interno que existe dentro daquela função, e se não houver

nenhum, é erro de sintaxe. É por isso que forEach não aceita break para

parar tudo — o break só sai do forEach.

Quando a intenção é parar a volta inteira, o laço é for...of com break, e

find devolve o item em vez de parar.

A função comBreakInterno do exemplo é exatamente esse caso. Ela tem um

for...of próprio sobre a lista de tarefas, e o break dentro dele sai desse

for, não de nenhum laço de fora — a chamada sai em

break dentro da funcao: estudar. Com 'treinar' na entrada, a volta 0 não

casou com o break, deu return item e devolveu 'estudar' na hora; o

treinar nunca chegou a ser comparado.

Exemplo

// for com contador e forEach, que e o laco que percorre o array.
const tarefas = ['estudar', 'treinar', 'descansar'];

/* for: o laco tem contador */
for (let i = 0; i < 3; i++) {
  console.log('i =', i);
}
// let dentro do for nao sobrevive ao laco: no fim das voltas o nome sumiu
try {
  console.log('i vale', i);
} catch (erro) {
  console.log('depois do laco:', erro.constructor.name, '-', erro.message);
}

/* o < fica e nao o <=: com <= seriam quatro voltas */
for (let i = 0; i <= 2; i++) console.log('volta', i);

/* o passo nao precisa ser i++ */
for (let i = 2; i <= 8; i += 2) console.log('de dois em dois:', i);
for (let i = 3; i > 0; i--) console.log('descendo:', i);

/* forEach: o array controla o numero de voltas */
tarefas.forEach((tarefa, indice) => {
  console.log('forEach:', indice, tarefa);
});

/* o escopo de cada volta e proprio */
const nomes = [];
for (const item of tarefas) {
  const marcado = item + '!';
  nomes.push(marcado);
}
console.log('marcados:', nomes);

/* forEach nao devolve nada */
const resultado = tarefas.forEach((t) => t.length);
console.log('retorno do forEach:', resultado);

/* break sai do laco inteiro */
for (const n of [1, 2, 3, 4, 5]) {
  if (n === 3) break;
  console.log('com break:', n);
}

/* continue pula para a proxima volta */
for (const n of [1, 2, 3, 4, 5]) {
  if (n % 2 === 0) continue;      // pula os pares
  console.log('com continue (impares):', n);
}

/* o contador de dentro do laco, que e o que o app usa para numerar a lista */
let total = 0;
tarefas.forEach(() => { total = total + 1; });
console.log('quantas tarefas:', total);

/* break dentro de uma funcao nao sai do for que a chamou */
function comBreakInterno(n) {
  for (const item of tarefas) {
    if (item === n) break;        // sai deste for, nao do de fora
    return item;
  }
  return 'nao achou';
}
console.log('break dentro da funcao:', comBreakInterno('treinar'));

Saída real

i = 0
i = 1
i = 2
depois do laco: ReferenceError - i is not defined
volta 0
volta 1
volta 2
de dois em dois: 2
de dois em dois: 4
de dois em dois: 6
de dois em dois: 8
descendo: 3
descendo: 2
descendo: 1
forEach: 0 estudar
forEach: 1 treinar
forEach: 2 descansar
marcados: [ 'estudar!', 'treinar!', 'descansar!' ]
retorno do forEach: undefined
com break: 1
com break: 2
com continue (impares): 1
com continue (impares): 3
com continue (impares): 5
quantas tarefas: 3
break dentro da funcao: estudar
Aula 2

while, for...of e for...in

while, for...of e for...in

A condição do laço é o que decide se ele repete. while repete enquanto a

condição for verdadeira, e a condição é conferida antes

de cada volta — igual ao for. A diferença é que o while não tem contador

pronto: se o passo estiver dentro do bloco, é preciso escrever.

let i = 0;
while (i < 3) {
  console.log(i);
  i++;
}

Esquecer o i++ produz laço infinito: o programa não volta a fazer nada

nunca, e o aparelho trava. Esse é o defeito mais caro do while, e a razão de o

for existir. O while serve quando o número de voltas não se sabe antes.

O exemplo imprime while: 0, while: 1 e while: 2 — três voltas para a mesma

condição do for da aula anterior, escritas em quatro linhas em vez de uma. O

i++ está na segunda linha do bloco, e é ele que impede a quarta volta: sem ele,

a condição i < 3 continuaria verdadeira para sempre.

A diferença para o for não está na forma de testar, e sim em onde fica o

passo: no for ele é uma das três partes do cabeçalho e não pode ser esquecido

por descuido visual; no while ele é uma linha do corpo, e o esquecimento

compila sem erro nenhum. É por isso que while em código de app costuma vir

acompanhado de um contador com nome óbvio.

No fim do exemplo há o while aplicado ao dado, que é o uso legítimo: um

contador restantes que começa em 3 e desce, imprimindo faltam 3 tarefas,

faltam 2 tarefas e faltam 1 tarefas. O laço termina quando restantes chega

a 0. Aqui o número de voltas é desconhecido no começo — depende do 3 — e

ainda assim a forma é a mesma do for com contador.

do...while confere a condição depois de executar, então o bloco roda pelo

menos uma vez, mesmo com condição já falsa:

let tentativas = 0;
do {
  tentativas++;
} while (tentativas < 3);
console.log(tentativas);   // 3

Com a condição já falsa na entrada, do...while dá 1 e while dá 0.

O exemplo deixa essa comparação na mesma linha, e é a forma mais direta de ver a

diferença:

do while com condicao falsa: 1 | while nem roda: 0. O 1 vem do

jaFalso++ executado antes de o JavaScript olhar o while (false); o 0 vem

da função anônima do lado direito, em que o while (false) nunca entra no

corpo. A linha anterior é o outro lado:

do while com condicao verdadeira: 3, com três voltas porque a condição só

falha na quarta.

O uso de do...while que aparece em app é a tentativa: rodar a ação, conferir o

resultado, repetir. do...while é o que garante que a primeira tentativa

existe, mesmo quando a condição já começa falsa.

for...of: o laço que percorre valor

for...of percorre um iterável — array, string, conjunto — e entrega o

valor, não a posição:

for (const item of ['estudar', 'treinar']) {
  console.log(item);
}

Para array e string, for...of é a escolha certa: o valor vem pronto, o nome da

variável diz o que ele é, e const funciona porque o valor nunca é reatribuído.

É o laço que o aluno vai escrever ao percorrer a lista de tarefas no componente.

O protocolo por trás é o Symbol.iterator, o mesmo que permite o for...of

funcionar em qualquer estrutura iterável.

O exemplo percorre os dois tipos na mesma seção. Sobre a lista de três tarefas,

imprime for...of: estudar, for...of: treinar e for...of: descansar — três

valores, e nenhum índice. Sobre a string 'Ana', imprime letra: A, letra: n e

letra: a: o for...of dividiu o texto em caracteres, e cada volta recebeu

um. Nenhum dos dois laços precisou de .length, .split nem contador.

Os dois laços de break e continue também estão no exemplo, e mostram que o

for...of é o laço que aceita os dois. Com break, sai uma linha só, porque

'treinar' interrompe. Com continue, saem duas — e 'treinar' foi o pulado. É

o mesmo comportamento da aula anterior, agora em cima do for...of.

for...in: o laço que percorre chave

for...in percorre os nomes das propriedades, e o nome sempre chega como

string. Em array, isso é quase sempre o que se não quer:

for (const chave in ['a', 'b']) {
  console.log(chave, typeof chave);   // '0' string, '1' string
}

A pegadinha clássica de for...in em array: o índice chega como string, e

qualquer conta feita com ele passa por conversão implícita. for...in é para

objeto, e mesmo nele a ordem das chaves não é garantida.

O exemplo passa a lista pelo for...in e imprime

for...in em array: 0 string, 1 string e 2 string. A palavra string no

fim de cada linha é o ponto: são três linhas que mostram exatamente o defeito.

O for...of da seção anterior imprimiu os valores; o for...in imprime as

posições — e como texto.

Em objeto ele funciona como se deve, e a linha sai completa:

for...in em objeto: nome = Ana, idade = 30 e ativo = true. Cada volta

recebeu a chave e leu o valor com usuario[chave]. Perceba que o acesso é por

colchete: com o valor da chave é a única forma de ler a propriedade em

variável.

A terceira passagem repete o for...in no array e imprime

indice do for...in: string | item pela chave: estudar, e o mesmo para

treinar e descansar. Ou seja: o item continua correto quando lido por

chave — o que quebra é quando o índice entra na conta. tarefas[chave] devolve

o texto certo; tarefas[chave] + 1 ou chave - 1 já fariam conversão

implícita silenciosa.

E a alternativa moderna sai nas três últimas linhas do grupo:

Object.keys: nome, Object.keys: idade, Object.keys: ativo. O

for...of sobre Object.keys(usuario) entrega as chaves como valores de

verdade, e o nome da variável é chave de novo — sem a conversão implícita e

com a lista de chaves disponível para o find e o includes depois.

Precisa deUse
o valor de um array ou stringfor...of
a chave de um objetofor...in, ou Object.keys()
parar com break no meiofor...of
número de voltas conhecidofor com contador

break e continue funcionam nos três. E forEach não aceita break para

parar tudo, porque o break sai do laço mais interno da função que o chamou e

forEach é um método, não um laço.

A linha da tabela que decide a escolha é a do break: for...of e for são

laços de verdade, e o break neles sai da lista inteira. A exceção é o

forEach, que não é laço — é método que recebe função, e o break que estiver

dentro dessa função sai do laço que ela tiver, não da lista do forEach.

É por isso que o exemplo do break usa for...of e não forEach, mesmo

percorriendo a mesma lista de tarefas: o parou em: estudar é a prova de que o

laço parou na primeira volta que não era a procurada, e não de que a lista

terminou.

Exemplo

// while, do while, for...of e for...in: os quatro lacos.
let i = 0;
while (i < 3) {
  console.log('while:', i);
  i++;
}

// do while confere a condicao depois: roda pelo menos uma vez
let tentativas = 0;
do {
  tentativas++;
} while (tentativas < 3);
console.log('do while com condicao verdadeira:', tentativas);

let jaFalso = 0;
do {
  jaFalso++;
} while (false);
console.log('do while com condicao falsa:', jaFalso, '| while nem roda:', (() => { let k = 0; while (false) { k++; } return k; })());

/* for...of entrega o VALOR */
const tarefas = ['estudar', 'treinar', 'descansar'];
for (const item of tarefas) {
  console.log('for...of:', item);
}

/* for...of tambem percorre string */
for (const letra of 'Ana') console.log('letra:', letra);

/* break e continue funcionam no for...of */
for (const item of tarefas) {
  if (item === 'treinar') break;
  console.log('parou em:', item);
}
for (const item of tarefas) {
  if (item === 'treinar') continue;
  console.log('pulou:', item);
}

/* for...in entrega a CHAVE, e a chave e string */
for (const chave in tarefas) {
  console.log('for...in em array:', chave, typeof chave);
}

/* for...in em objeto: o uso correto dele */
const usuario = { nome: 'Ana', idade: 30, ativo: true };
for (const chave in usuario) {
  console.log('for...in em objeto:', chave, '=', usuario[chave]);
}

/* a pegadinha: dentro do for...in, o indice e string */
for (const chave in tarefas) {
  console.log('indice do for...in:', typeof chave, '| item pela chave:', tarefas[chave]);
}

/* a alternativa moderna a for...in: Object.keys */
for (const chave of Object.keys(usuario)) {
  console.log('Object.keys:', chave);
}

/* laco com condicao que depende do dado: while e a escolha natural */
let restantes = 3;
while (restantes > 0) {
  console.log('faltam', restantes, 'tarefas');
  restantes--;
}

Saída real

while: 0
while: 1
while: 2
do while com condicao verdadeira: 3
do while com condicao falsa: 1 | while nem roda: 0
for...of: estudar
for...of: treinar
for...of: descansar
letra: A
letra: n
letra: a
parou em: estudar
pulou: estudar
pulou: descansar
for...in em array: 0 string
for...in em array: 1 string
for...in em array: 2 string
for...in em objeto: nome = Ana
for...in em objeto: idade = 30
for...in em objeto: ativo = true
indice do for...in: string | item pela chave: estudar
indice do for...in: string | item pela chave: treinar
indice do for...in: string | item pela chave: descansar
Object.keys: nome
Object.keys: idade
Object.keys: ativo
faltam 3 tarefas
faltam 2 tarefas
faltam 1 tarefas