Alura > Cursos de Programação > Cursos de > Conteúdos de > Primeiras aulas do curso Praticando JavaScript: laços de repetição

Praticando JavaScript: laços de repetição

JavaScript Loops - Apresentação

Olá! Boas-vindas ao curso da formação de Prática de Programação com JavaScript. Meu nome é Ju Amoasei.

Audiodescrição: Ju se descreve como uma mulher branca, de cabelo curto pintado de azul e olhos castanhos. Usa óculos de armação vermelha, piercing no nariz, brinco de argola e camiseta cinza. Ao fundo, estúdios da Alura com iluminação azulada e estante com decorações.

O foco deste curso é realmente praticar com código, testar nossos conhecimentos de forma ativa e resolver alguns dos problemas de lógica de programação que encontramos durante nossa rotina de estudos.

O que aprenderemos?

Nessa formação, teremos revisão de conteúdo, material suplementar e muitos desafios e exercícios para realmente colocarmos em prática tudo o que aprendemos.

Quais são os requisitos?

É importante destacar que, como este é um curso de revisão, é necessário já ter concluído a formação anterior, que é a formação de fundamentos de JavaScript para back-end, onde apresentamos os conceitos que apenas revisaremos durante esta formação.

Nessa formação de prática, o conteúdo será revisado de forma incremental. Portanto, é recomendável seguir os cursos na ordem apresentada, para garantir que não percamos nada que seja referenciado em revisões anteriores.

É importante notar que este curso não é voltado para front-end. No entanto, toda prática realizada com JavaScript pode ser aproveitada no front-end, desde que o Node.js esteja instalado.

É essencial pausar, testar os vídeos, experimentar os exemplos, modificar e fazer os exercícios. Isso é muito importante e será enfatizado durante toda a revisão. Além disso, podemos compartilhar o que aprendemos no fórum e pedir ajuda, se necessário.

Vamos começar?

JavaScript Loops - Laço For

Vamos revisar laços de repetição, ou loops, como chamamos em JavaScript e em outras linguagens também.

Entendendo o que são laços de repetição

O JavaScript, basicamente, possui três laços de repetição nativos:

Existem outros tipos de instrução que podemos utilizar no JavaScript que também têm esse comportamento repetitivo, como, por exemplo:

Neste curso, vamos focar em for, while e do... while, pois os outros são mais específicos. Vamos abordar for... of e for... in ao abordar arrays e objetos em outros cursos.

Explorando sintaxe do laço for

Para começar, vamos nos concentrar no laço for, que é o tipo de laço de repetição mais utilizado. Ele possui uma forma semelhante em diversas linguagens, pelo menos nas mais usadas, e é o mais comum quando estamos praticando lógica de programação e resolução de algoritmos, devido à sua versatilidade. Vamos relembrar a sintaxe dele:

for (inicialização; condição; atualização) {

}

Começamos declarando o for, ou seja, nosso laço. Em seguida, entre parênteses, colocamos três instruções. A primeira instrução, de inicialização, é executada uma única vez, antes de tudo começar, antes mesmo do for verificar se vai realizar a primeira iteração ou não.

A segunda instrução é a condição, também chamada de condição de parada ou de continuidade, que é avaliada antes de cada iteração. Assim, se o código chegar na linha do for, essa condição for avaliada e resultar em false (falso), nem a primeira iteração será realizada. Porém, se a primeira iteração ocorrer, voltamos e avaliamos a condição novamente antes de fazer a segunda.

Por último, a atualização é executada antes de começar um laço e depois de terminar o laço anterior. Assim, entramos no laço, executamos o código dentro do bloco e, antes de verificar se entramos novamente no loop para uma nova iteração, executamos o que estiver nessa instrução.

As instruções devem estar separadas por ponto e vírgula - e nenhuma delas é obrigatória. Durante os estudos, podemos encontrar casos que podem não precisar de uma ou outra instrução.

Exemplificando código com tabuada de 5

Dando um exemplo usando JavaScript, criamos uma const chamada numero para fazer uma tabuada de 5. Queremos um código que multiplique 5 de 1 a 10, ou seja, 5 vezes 1, 5 vezes 2, 5 vezes 3 e assim por diante.

As três instruções — inicialização, condição e atualização — referem-se a isso. Na inicialização, criamos uma let chamada i - que é um nome padrão, mas podemos usar qualquer nome. Iniciamos essa let i com o número 1. Nesse caso, ela será responsável por contar as iterações. Começamos no 1 porque queremos que vá de 1 até 10.

A segunda instrução é a condição para entrar ou não no laço. Queremos que isso aconteça enquanto o valor da variável i for menor ou igual a 10, pois queremos que pare no 10. Assim, paramos quando calculamos 5 vezes 10 igual a 50.

Desse modo, a primeira iteração vai acontecer, pois acabamos de criar a let i com o valor de 1. Como 1 é menor que 10, a condição retorna true (verdadeiro). A lógica funciona assim como no if e em outras condicionais: entra no bloco enquanto a avaliação da expressão for verdadeira. No momento em que resultar em falso, saímos do laço.

A terceira instrução é a atualização, onde incrementamos o valor da variável i.

const numero = 5;

for (let i = 1; i <= 10; i++) {
    const resultado = numero * i;
    console.log(`${numero} x ${i} = ${resultado}`);
}

Na prática, entramos no primeiro laço, criamos uma const chamada resultado para guardar o resultado da tabuada. Na primeira vez que entramos, nosso número base é sempre 5, que será multiplicado por i.

Na primeira iteração do laço, i é 1. Então, 5 vezes 1 é igual a 5, que é guardado na const resultado e exibido no console.

Finalizado o bloco, antes de verificar se haverá mais um laço, atualizamos o valor de i. Isso significa que, quando a condição for avaliada novamente, i não vale mais 1, mas sim 2, pois a atualização já foi feita.

Lembrando que i++ equivale a i = i + 1, enquanto i-- equivale a i = i - 1. Sempre que queremos incrementar um valor numérico de 1 em 1, podemos usar essa sintaxe reduzida, que é bastante comum em laços.

Seguimos esse fluxo até chegar no 10. Quando o valor de i for 10, realizamos a operação 5 vezes 10, e o valor de let i será atualizado para 11. A condição 11 menor ou igual a 10 resultará em falso, e não entraremos mais no laço.

Note que estamos criando uma const dentro do for. As variáveis criadas dentro do for são recriadas a cada laço, então a const resultado guardará o número enquanto o laço estiver executando. Na próxima iteração, ela será recriada com um novo número, existindo apenas dentro do laço.

Evitando loop infinito

Quando trabalhamos com for, é comum enfrentarmos um problema chamado loop infinito. Isso ocorre quando um laço continua a executar sem parar, geralmente devido a um erro no código que impede a condição de saída.

Vamos apresentar dois exemplos na tabuada de 5 para ilustrar como um loop infinito pode ocorrer.

Primeiramente, se esquecermos de incluir a condição de atualização ou incremento da variável i, o valor de i nunca será alterado. Assim, i nunca atingirá 11. Logo, a condição de continuidade no laço sempre será verdadeira, pois i sempre será menor ou igual a 10. Como i permanece 1, o laço executará indefinidamente, caracterizando um loop infinito.

const numero = 5;

for (let i = 1; i <= 10; ) {
    const resultado = numero * i;
    console.log(`${numero} x ${i} = ${resultado}\n`);
}

Ressaltamos que o fato de não existir uma instrução de atualização não é considerado um erro pelo JavaScript. Afinal, às vezes não precisamos de uma das três instruções.

Outro exemplo ocorre quando, ao trabalhar com operadores, invertemos o sinal da condição sem querer. Em vez de i ser menor ou igual a 10, escrevemos que a condição de continuidade será enquanto i for maior ou igual a 0.

Se i for inicializado com um valor maior que 0, como 1, e for incrementado, i sempre será maior ou igual a 0. Assim, o laço continuará executando sem parar.

const numero = 5;

for (let i = 1; i >= 0; i++) {
    const resultado = numero * i;
    console.log(`${numero} x ${i} = ${resultado}\n`);
}

Normalmente, o programa empilha as instruções que lhe são passadas e as executa na ordem de pilha. Um exemplo de instrução é a linha const resultado = numero * i. Quando temos um loop infinito, as instruções se empilham indefinidamente até que o programa não consiga mais lidar com essa pilha.

Simplificadamente, quando a memória não consegue mais guardar essa pilha, isso resulta no que chamamos de estouro de pilha ou stack overflow. Isso pode travar o computador, pois está relacionado à memória disponível para o programa executar.

Atualmente, tanto o Node.js quanto os navegadores modernos possuem ferramentas para lidar com esse problema, interrompendo o laço quando detectam um possível estouro de pilha.

Se isso ocorrer, não se preocupe, é comum enfrentar loops infinitos acidentalmente. Revise o código e, se o console.log() estiver rodando indefinidamente, pressione "Ctrl + C" para interromper o processo.

Após iniciar o laço, o programa só continua executando o restante do código quando finalizar as iterações do laço.

Isso causa o loop infinito, pois o programa continua executando as iterações sem uma instrução de saída.

Gerenciando saídas com break e continue

Uma forma de gerenciar essas saídas do laço é utilizando o break, a mesma instrução que utilizamos no switch para sair do bloco de condicionais.

Para exemplificar, vamos trazer um código que gera 50 números aleatórios de 1 a 50 através do Math.random().

O break interrompe o laço quando encontrado, independentemente da condição de continuidade ainda ser verdadeira.

Por exemplo, esse laço vai até 50, mas se encontrar o break antes, ele interrompe o laço na iteração em que o break aparece e continua com o restante do código.

for (let contador = 1; contador <= 50; contador++) {
    const numero = Math.floor(Math.random() * (50 - 1 + 1) + 1);
    if (numero === 15) {
        console.log(`${numero} em ${contador} tentativas`);
        break;
    }
}

Outra forma de manejar laços é usando o continue.

O continue pula para a próxima iteração e desconsidera o restante do bloco atual.

Por exemplo, suponha que dentro do for, há um bloco de código com várias instruções. Ao encontrar o continue, a iteração é interrompida imediatamente, ignorando o restante das instruções, e passa para a próxima iteração.

let contador = 0;

for (let i = 1; i <= 20; i++) {
    const numero = Math.floor(Math.random() * (50 - 1 + 1) + 1);
    if (numero % 5 === 0) {
        continue;
    }
    contador++;
}
console.log('contador', contador);

Assim, o continue não interrompe o laço, apenas a iteração atual. Com isso, conseguimos gerenciar o laço e não executar exatamente o mesmo código em todas as iterações.

Conclusão

Vamos praticar e colocar esses conceitos em ação, executando os códigos para observar o funcionamento do break e do continue.

JavaScript Loops - Prática For

Voltando ao Visual Studio Code, vamos praticar com os exemplos de break e continue abordados na revisão.

Criando o laço for com break

O primeiro código deve gerar números aleatórios de 1 a 50 e interromper o laço caso o número gerado seja 15. O laço também será interrompido após 30 tentativas, mas você pode ajustar essa quantidade caso queira. Além disso, é preciso contar a quantidade de tentativas realizadas.

Primeiramente, vamos criar o laço for. Precisamos que esse laço rode 50 vezes, portanto, precisamos contar de 1 até 50. Por isso, na instrução de inicialização, criaremos uma let i igual a 1.

Na condição de parada, vamos configurá-lo para parar após 30 tentativas. Isto é, o código executa enquanto i for menor ou igual a 30. Por fim, na instrução de atualização, vamos incrementar i++ a cada iteração para conseguir alcançar a condição de parada.

for (let i = 1; i <= 30; i++) {

}

Para gerar um número aleatório no JavaScript, utilizaremos a biblioteca nativa chamada Math. Ela possui alguns métodos para realizar operações matemáticas.

Você pode conferir a documentação do Math.random() do MDN para conhecer mais sobre esse método que gera números aleatórios.

Já deixamos o código pronto para criar uma constante numero que armazenará o número aleatório gerado em cada iteração:

for (let i = 1; i <= 30; i++) {
    const numero = Math.floor(Math.random() * (50 - 1 + 1) + 1);
}

O método Math.random() gera um número aleatório entre 0 e 1, e ao multiplicá-lo por 50 e somar 1, obtemos um número entre 1 e 50. Englobamos esse código com o método Math.floor() da mesma biblioteca. Esse método arredonda o número para baixo, retirando as casas decimais e garantindo que seja um inteiro.

Agora que já geramos números aleatórios de 1 a 50, precisamos interromper o laço caso o número gerado seja 15. Para isso, utilizamos um condicional if. Se numero for estritamente igual (===) a 15, o break é acionado, interrompendo o laço.

Antes disso, registramos a quantidade de tentativas com console.log(). Nele, vamos concatenar textos e variáveis com a seguinte template string: ${numero} em ${i} tentativas.

for (let i = 1; i <= 30; i++) {
    const numero = Math.floor(Math.random() * (50 - 1 + 1) + 1);
    if (numero === 15) {
        console.log(`${numero} em ${i} tentativas`);
        break;
    }
}

Assim, depois que imprimimos a mensagem no console com a quantidade de tentativas, interrompemos o laço, caso o número aleatório gerado seja 15, e continuamos a executar o restante do código - independentemente de qual iteração estávamos.

Para tornar o código mais claro, substituímos o nome da variável i por contador. Afinal, a variável inicial não apenas controla o laço, mas também conta as iterações.

for (let contador = 1; contador <= 30; contador++) {
    const numero = Math.floor(Math.random() * (50 - 1 + 1) + 1);
    if (numero === 15) {
        console.log(`${numero} em ${contador} tentativas`);
        break;
    }
}

Finalmente, podemos executar o código. No terminal integrado, dentro da pasta correta, executamos o comando node e o nome do arquivo:

node exercicios.js

Se não retornar nada, pode ser que em 30 tentativas o número 15 não tenha sido gerado aleatoriamente. Portanto, nenhuma mensagem foi impressa no console.

Vamos fazer uma nova tentativa? Se o número 15 for gerado, o console indicará em quantas tentativas isso ocorreu:

15 em 11 tentativas

O primeiro exercício foi concluído com sucesso! O break funciona e, inclusive, mostra a iteração em que o laço parou.

Criando o laço com continue

Vamos continuar com o próximo exercício da revisão, que utiliza o continue. Novamente, geraremos números aleatórios de 1 a 50, mas agora o contador será incrementado somente caso os números não sejam divisíveis por 5.

Em outras palavras, precisamos de uma maneira de contar as iterações, mas pular números como, por exemplo, 5, 10, 15, 20 ou 25. Se gerar um desses números, o contador não pode ser incrementado. Portanto, o contador e a variável de inicialização precisarão ser diferentes.

Primeiro, vamos criar um laço for. Para controlar quantas vezes o laço é executado, vamos criar uma let i que começa com o valor 1.

Queremos que o laço executando por 30 iterações, portanto, vamos definir a condição como 1 menor ou igual a 30. Além disso, manteremos a instrução de incremento do i como i++.

Para gerar um número aleatório, vamos reutilizar a linha que cria a constante numero, a qual armazena um número inteiro de 1 a 50.

for (let i = 1; i <= 30; i++) {
    const numero = Math.floor(Math.random() * (50 - 1 + 1) + 1);
}

Agora, precisamos criar uma condicional, pois queremos verificar se o número aleatório gerado não é divisível por 5 para poder incrementar o contador.

Antes disso, precisamos primeiro criar uma variável contador, fora do for, para contar as iterações em que o número não é divisível por 5. Essa variável não pode ficar dentro do laço, já que nem sempre deve ser atualizada.

Em seguida, no laço, basta fazer um if com a condição numero % 5 é estritamente igual (===) a zero. Ou seja, verificamos se o número gerado é divisível por 5.

Dica: o operador de módulo (%) retorna o resto da divisão do primeiro pelo segundo número.

Caso isso seja verdadeiro, vamos utilizar o continue para interromper a iteração atual e volta ao início do for para começar uma nova iteração. Assim, o continue interrompe antes de executar o código que estiver depois dele nesse bloco for. Por isso, depois do if, precisamos incrementar contador++.

let contador = 0;

for (let i = 1; i <= 30; i++) {
    const numero = Math.floor(Math.random() * (50 - 1 + 1) + 1);
    if (numero % 5 === 0) {
        continue;
    }
    contador++;
}

Com isso, se o número aleatório gerado for divisível por 5, entramos na condicional e acionamos o continue. Nesse momento, saímos da iteração atual e passamos para a próxima, ignorando o incremento do contador.

Ou seja, agora temos uma variável para gerenciar os laços e garantir que sejam executados 30 vezes. E temos outra variável apenas para contar a quantidade de iterações, caso o número não seja divisível por 5.

Por fim, devemos verificar o valor da variável contador. Para isso, fazemos um console.log() de contador, depois do for. Assim, só quando o laço acabar é que vamos imprimir esse valor do contador no console.

console.log(contador);

No terminal, executamos o comando node exercicios.js. Verificamos que, em 30 tentativas, seis números eram divisíveis por 5 e foram ignorados.

24

Criando duas variáveis na mesma linha

No JavaScript, existe uma sintaxe que permite criar mais de uma variável por linha. Então, seria possível criar uma let i = 1 na inicialização do for, acrescentar uma vírgula, ainda na primeira instrução, e inicializar contador com zero.

Exemplo:

// let contador = 0;

for (let i = 1, contador = 0; i <= 30; i++) {
    const numero = Math.floor(Math.random() * (50 - 1 + 1) + 1);
    if (numero % 5 === 0) {
        continue;
    }
    contador++;
}

console.log(contador);

O JavaScript aceita isso, mesmo fora do for, é uma sintaxe que você pode usar no seu dia a dia. Pessoalmente, a Ju não gosta muito de usar essa sintaxe. Ela prefere colocar uma declaração embaixo da outra, porque fica mais explícito.

Mas, é possível usá-la caso você queira criar mais de uma variável para ser gerenciada dentro desse loop. No entanto, ela talvez não funcione tão bem no nosso exemplo. Vamos testar?

Quando executamos node exercicios.js, acontece um erro. Vamos analisar esse erro:

ReferenceError: contador is not defined.

Nesse exemplo, a variável contador foi criada dentro do laço for. Quando saímos desse bloco, as variáveis que foram criadas dentro dele não existem do lado de fora.

Se quiséssemos apenas passar console.log() de contador dentro do for, conseguiríamos executar o código. Assim, imprimiríamos no console todas as iterações que geraram um número não divisível por 5.

Contudo, como queremos que a variável contador seja populada com dados do for, mas que exista fora desse laço, precisamos declará-la do lado de fora. Por isso, vamos manter o código como já havíamos desenvolvido anteriormente.

Conclusão

O laço for é bem versátil! Conseguimos fazer vários tipos de operações matemáticas, expressões e até várias verificações com a declaração de mais de uma variável. Por isso que ele é tão usado em problemas de lógica de programação e algoritmos.

Vamos continuar praticando outros casos de laços de repetição no JavaScript para consolidar esses conceitos.

Sobre o curso Praticando JavaScript: laços de repetição

O curso Praticando JavaScript: laços de repetição possui 49 minutos de vídeos, em um total de 20 atividades. Gostou? Conheça nossos outros cursos de em Programação, ou leia nossos artigos de Programação.

Matricule-se e comece a estudar com a gente hoje! Conheça outros tópicos abordados durante o curso:

Aprenda acessando integralmente esse e outros cursos, comece hoje!

Conheça os Planos para Empresas