Os laços while e do...while são estruturas de repetição fundamentais em JavaScript que executam um bloco de código enquanto uma condição especificada for verdadeira. Diferentemente do for, que é mais adequado quando sabemos o número de iterações, esses laços são ideais para situações em que a repetição depende de uma condição que pode mudar durante a execução. Nesta aula, vamos explorar suas diferenças, como definir condições de parada seguras e como evitar loops infinitos, um erro comum que pode travar seu programa.

Entender o comportamento desses laços é essencial para escrever código eficiente e evitar bugs. Vamos começar com as diferenças entre while e do...while.

Diferenças

A principal diferença entre while e do...while está no momento em que a condição é avaliada. No laço while, a condição é testada antes da execução do bloco de código. Se a condição for falsa desde o início, o bloco nunca será executado. Já no do...while, o bloco é executado pelo menos uma vez, e a condição é testada após a primeira execução. Isso garante que o código dentro do do...while sempre rode pelo menos uma vez, independentemente da condição.

Essa diferença é crucial em situações onde você precisa garantir que uma ação ocorra antes de verificar se deve continuar. Por exemplo, ao solicitar entrada do usuário até que seja válida, muitas vezes é mais natural usar do...while para exibir a mensagem ao menos uma vez.

Exemplo prático:

// while: condição testada antes
let i = 10;
while (i < 5) {
  console.log('Este código não será executado');
}

// do...while: condição testada depois
let j = 10;
do {
  console.log('Este código será executado uma vez');
} while (j < 5);

No primeiro exemplo, a condição i < 5 é falsa desde o início, então o bloco nunca é executado. No segundo, o bloco é executado uma vez antes de a condição ser testada.

Condições de parada

A condição de parada é a expressão booleana que determina se o laço continua ou não. Enquanto a condição for true, o laço continua; quando se torna false, o laço para. É fundamental que a condição eventualmente se torne falsa, caso contrário teremos um loop infinito. A condição pode ser qualquer expressão que resulte em um valor booleano, como comparações (>, <, ===), chamadas de função ou mesmo variáveis.

Exemplo de condição de parada com contador:

let contador = 0;
while (contador < 5) {
  console.log('Iteração ' + contador);
  contador++;
}

Aqui, a condição é contador < 5. A cada iteração, incrementamos o contador, garantindo que eventualmente a condição se torne falsa. Se esquecermos de atualizar o contador, o laço nunca pararia.

Outro exemplo com condição baseada em entrada do usuário (simulado):

let resposta;
do {
  resposta = prompt('Digite "sair" para encerrar:');
} while (resposta !== 'sair');

Nesse caso, a condição verifica se a resposta é diferente de "sair". O laço continua até que o usuário digite "sair".

Loops infinitos (e como evitar)

Um loop infinito ocorre quando a condição do laço nunca se torna falsa, fazendo com que o bloco seja executado indefinidamente. Isso pode travar o navegador ou o ambiente de execução, consumindo toda a CPU e memória. As causas comuns são: esquecer de atualizar a variável de controle, condição sempre verdadeira, ou erro de lógica.

Exemplo de loop infinito:

let i = 0;
while (i < 10) {
  console.log(i);
  // esquecemos de incrementar i
}

Para evitar loops infinitos, siga estas boas práticas:

  • Atualize a variável de controle: Certifique-se de que dentro do laço haja uma instrução que modifique a condição (ex: incremento, decremento, mudança de estado).
  • Verifique a condição: Garanta que a condição pode se tornar falsa em algum momento. Evite condições como true ou 1 === 1 sem uma saída explícita com break.
  • Use um contador máximo: Em loops potencialmente perigosos, adicione um contador de segurança que interrompa o laço após um número máximo de iterações.
  • Teste com valores pequenos: Antes de executar em produção, teste o laço com poucas iterações para verificar se ele termina.

Exemplo com contador de segurança:

let maxIteracoes = 1000;
let contador = 0;
while (condicao) {
  // código
  contador++;
  if (contador > maxIteracoes) {
    console.log('Loop interrompido por segurança');
    break;
  }
}

Outra forma de evitar loops infinitos é usar a instrução break para sair do laço quando uma condição específica for atendida, mesmo que a condição principal ainda seja verdadeira.

Boas práticas e observações finais

Ao escolher entre while e do...while, prefira while quando não houver necessidade de executar o bloco pelo menos uma vez. Use do...while quando a ação deve ocorrer ao menos uma vez antes da verificação. Sempre garanta que a condição de parada seja clara e que o laço tenha um fim definido. Evite modificar variáveis de controle dentro do laço de maneira imprevisível. Lembre-se de que loops infinitos podem causar travamentos, então teste cuidadosamente.

Referências

Exercícios

  1. Escreva um laço while que exiba os números de 1 a 10 no console.

    ✓ Resposta:
    let i = 1;
    while (i <= 10) {
      console.log(i);
      i++;
    }
    
  2. Usando do...while, peça ao usuário que digite um número maior que 10. Repita até que ele digite um número válido. (Simule com uma variável fixa para teste).

    ✓ Resposta:
    let numero;
    do {
      numero = parseInt(prompt('Digite um número maior que 10:'));
    } while (numero <= 10);
    console.log('Número válido:', numero);
    
  3. O que acontece no código abaixo? Corrija para evitar um loop infinito.

    let x = 0;
    while (x < 5) {
      console.log(x);
      x--;
    }
    

    ✓ Resposta:

    O código decrementa x em vez de incrementar, então x fica cada vez menor, nunca atingindo 5. Para corrigir, troque x-- por x++.

    let x = 0;
    while (x < 5) {
      console.log(x);
      x++;
    }
    
  4. Escreva um laço while que percorra um array de nomes e exiba cada nome no console. Use o array ['Ana', 'Bruno', 'Carla'].

    ✓ Resposta:
    const nomes = ['Ana', 'Bruno', 'Carla'];
    let i = 0;
    while (i < nomes.length) {
      console.log(nomes[i]);
      i++;
    }
    
  5. Crie um laço do...while que gere números aleatórios entre 1 e 6 (simulando um dado) até que o número 6 seja sorteado. Exiba cada resultado.

    ✓ Resposta:
    let resultado;
    do {
      resultado = Math.floor(Math.random() * 6) + 1;
      console.log('Resultado:', resultado);
    } while (resultado !== 6);
    console.log('Parou!');