Muitas vezes precisamos repetir ações.
Por exemplo, exibir mercadorias de uma lista uma após a outra ou apenas executar o mesmo código para cada número de 1 a 10.
Loops são uma forma de repetir o mesmo código várias vezes.
Os loops for…of e for…in
Um pequeno anúncio para leitores avançados.
Este artigo cobre apenas loops básicos: while
, do..while
e for(..;..;..)
.
Se você veio a este artigo procurando outros tipos de loops, aqui estão as dicas:
Consulte for…in para fazer um loop nas propriedades do objeto.
Consulte for…of e iteráveis para fazer loop em arrays e objetos iteráveis.
Caso contrário, continue lendo.
O loop while
possui a seguinte sintaxe:
enquanto (condição) { //código // chamado "corpo de loop" }
Embora a condition
seja verdadeira, o code
do corpo do loop é executado.
Por exemplo, o loop abaixo gera i
while i < 3
:
seja i = 0; while (i <3) { // mostra 0, depois 1 e depois 2 alerta(eu); eu++; }
Uma única execução do corpo do loop é chamada de iteração . O loop no exemplo acima faz três iterações.
Se i++
estivesse faltando no exemplo acima, o loop se repetiria (em teoria) para sempre. Na prática, o navegador fornece maneiras de interromper esses loops e, no JavaScript do lado do servidor, podemos encerrar o processo.
Qualquer expressão ou variável pode ser uma condição de loop, não apenas comparações: a condição é avaliada e convertida em booleano por while
.
Por exemplo, uma maneira mais curta de escrever while (i != 0)
é while (i)
:
seja i = 3; while (i) { // quando i se torna 0, a condição se torna falsa e o loop para alerta(eu); eu--; }
Aparelhos encaracolados não são necessários para um corpo de linha única
Se o corpo do loop tiver uma única instrução, podemos omitir as chaves {…}
:
seja i = 3; enquanto (i) alerta(i--);
A verificação da condição pode ser movida abaixo do corpo do loop usando a sintaxe do..while
:
fazer { //corpo do loop } while (condição);
O loop primeiro executará o corpo, depois verificará a condição e, embora seja verdade, executará novamente e novamente.
Por exemplo:
seja i = 0; fazer { alerta(eu); eu++; } enquanto (i <3);
Esta forma de sintaxe só deve ser usada quando você deseja que o corpo do loop seja executado pelo menos uma vez, independentemente da condição ser verdadeira. Normalmente, a outra forma é preferida: while(…) {…}
.
O loop for
é mais complexo, mas também é o loop mais comumente usado.
Parece assim:
for (início; condição; passo) { // ... corpo do loop ... }
Vamos aprender o significado dessas partes com um exemplo. O loop abaixo executa alert(i)
for i
de 0
até (mas não incluindo) 3
:
for (seja i = 0; i < 3; i++) { // mostra 0, depois 1 e depois 2 alerta(eu); }
Vamos examinar a instrução for
parte por parte:
papel | ||
---|---|---|
começar | let i = 0 | Executa uma vez ao entrar no loop. |
doença | i < 3 | Verificado antes de cada iteração do loop. Se for falso, o loop será interrompido. |
corpo | alert(i) | É executado repetidamente enquanto a condição é verdadeira. |
etapa | i++ | Executa após o corpo em cada iteração. |
O algoritmo de loop geral funciona assim:
Corra, comece → (se condição → executar corpo e executar etapa) → (se condição → executar corpo e executar etapa) → (se condição → executar corpo e executar etapa) → ...
Ou seja, begin
é executado uma vez e depois itera: após cada teste condition
, body
e step
são executados.
Se você é novo em loops, pode ser útil voltar ao exemplo e reproduzir como ele é executado passo a passo em um pedaço de papel.
Aqui está exatamente o que acontece no nosso caso:
// for (seja i = 0; i < 3; i++) alert(i) //executa início deixe eu = 0 // if condição → executa o corpo e executa a etapa if (i <3) { alerta(i); eu++ } // if condição → executa o corpo e executa a etapa if (i <3) { alerta(i); eu++ } // if condição → executa o corpo e executa a etapa if (i <3) { alerta(i); eu++ } // ...terminar, porque agora i == 3
Declaração de variável embutida
Aqui, a variável “contador” i
é declarada diretamente no loop. Isso é chamado de declaração de variável “inline”. Tais variáveis são visíveis apenas dentro do loop.
for (seja i = 0; i < 3; i++) { alerta(eu); //0, 1, 2 } alerta(eu); //erro, essa variável não existe
Em vez de definir uma variável, poderíamos usar uma já existente:
seja i = 0; for (i = 0; i < 3; i++) { // usa uma variável existente alerta(eu); //0, 1, 2 } alerta(eu); // 3, visível, porque declarado fora do loop
Qualquer parte do for
pode ser ignorada.
Por exemplo, podemos omitir begin
se não precisarmos fazer nada no início do loop.
Como aqui:
seja i = 0; // já declaramos e atribuímos for (; i < 3; i++) { // não há necessidade de "begin" alerta(eu); //0, 1, 2 }
Também podemos remover a parte step
:
seja i = 0; para (; eu < 3;) { alerta(i++); }
Isso torna o loop idêntico a while (i < 3)
.
Na verdade, podemos remover tudo, criando um loop infinito:
para (;;) { //repete sem limites }
Observe que os dois for
ponto e vírgula ;
deve estar presente. Caso contrário, haveria um erro de sintaxe.
Normalmente, um loop termina quando sua condição se torna falsa.
Mas podemos forçar a saída a qualquer momento usando a diretiva especial break
.
Por exemplo, o loop abaixo pede ao usuário uma série de números, “quebrando” quando nenhum número é inserido:
seja soma = 0; enquanto (verdadeiro) { deixe valor = +prompt("Digite um número", ''); if (!valor) quebra; // (*) soma += valor; } alerta('Soma: ' + soma);
A diretiva break
é ativada na linha (*)
se o usuário inserir uma linha vazia ou cancelar a entrada. Ele interrompe o loop imediatamente, passando o controle para a primeira linha após o loop. Ou seja, alert
.
A combinação “loop infinito + break
conforme necessário” é ótima para situações em que a condição de um loop deve ser verificada não no início ou no final do loop, mas no meio ou mesmo em vários locais de seu corpo.
A diretiva continue
é uma “versão mais leve” de break
. Isso não interrompe todo o ciclo. Em vez disso, interrompe a iteração atual e força o loop a iniciar uma nova (se a condição permitir).
Podemos usá-lo se terminarmos a iteração atual e quisermos passar para a próxima.
O loop abaixo usa continue
para gerar apenas valores ímpares:
for (seja i = 0; i < 10; i++) { // se verdadeiro, pula a parte restante do corpo se (i% 2 == 0) continuar; alerta(eu); // 1, depois 3, 5, 7, 9 }
Para valores pares de i
, a diretiva continue
interrompe a execução do corpo e passa o controle para a próxima iteração de for
(com o próximo número). Portanto, o alert
só é chamado para valores ímpares.
A diretiva continue
ajuda a diminuir o aninhamento
Um loop que mostra valores ímpares poderia ser assim:
for (seja i = 0; i < 10; i++) { se (eu% 2) { alerta(eu); } }
Do ponto de vista técnico, isto é idêntico ao exemplo acima. Certamente, podemos simplesmente agrupar o código em um bloco if
em vez de usar continue
.
Mas, como efeito colateral, isso criou mais um nível de aninhamento (a chamada alert
dentro das chaves). Se o código dentro de if
tiver mais do que algumas linhas, isso poderá diminuir a legibilidade geral.
Sem break/continue
para o lado direito de '?'
Observe que construções de sintaxe que não são expressões não podem ser usadas com o operador ternário ?
. Em particular, diretivas como break/continue
não são permitidas lá.
Por exemplo, se pegarmos este código:
se (eu > 5) { alerta(eu); } outro { continuar; }
…e reescreva-o usando um ponto de interrogação:
(eu > 5) ? alerta(i): continuar; // continuar não é permitido aqui
…para de funcionar: há um erro de sintaxe.
Este é apenas mais um motivo para não usar o operador de ponto de interrogação ?
em vez de if
.
Às vezes, precisamos sair de vários loops aninhados de uma só vez.
Por exemplo, no código abaixo fazemos um loop sobre i
e j
, solicitando as coordenadas (i, j)
de (0,0)
a (2,2)
:
for (seja i = 0; i < 3; i++) { for (seja j = 0; j < 3; j++) { deixe input = prompt(`Valor nas coordenadas (${i},${j})`, ''); // e se quisermos sair daqui para Concluído (abaixo)? } } alerta('Concluído!');
Precisamos de uma maneira de interromper o processo se o usuário cancelar a entrada.
A break
comum após input
interromperia apenas o loop interno. Isso não é suficiente – rótulos, venham em socorro!
Um rótulo é um identificador com dois pontos antes de um loop:
nomedarótulo: para (...) { ... }
A instrução break <labelName>
no loop abaixo vai para o rótulo:
exterior: for (seja i = 0; i < 3; i++) { for (seja j = 0; j < 3; j++) { deixe input = prompt(`Valor nas coordenadas (${i},${j})`, ''); // se for uma string vazia ou cancelada, então interrompa ambos os loops if (!input) quebra externa; // (*) //faça algo com o valor... } } alerta('Concluído!');
No código acima, break outer
procura o rótulo chamado outer
e sai desse loop.
Então o controle vai direto de (*)
para alert('Done!')
.
Também podemos mover o rótulo para uma linha separada:
exterior: para (seja i = 0; i < 3; i++) { ... }
A diretiva continue
também pode ser usada com um rótulo. Neste caso, a execução do código salta para a próxima iteração do loop rotulado.
As etiquetas não permitem “pular” para lugar nenhum
Os rótulos não nos permitem pular para um lugar arbitrário no código.
Por exemplo, é impossível fazer isso:
quebrar rótulo; // pula para o rótulo abaixo (não funciona) rótulo: para (...)
Uma diretiva break
deve estar dentro de um bloco de código. Tecnicamente, qualquer bloco de código rotulado servirá, por exemplo:
rótulo: { // ... quebrar rótulo; // funciona // ... }
…Embora 99,9% do break
de tempo seja usado dentro de loops, como vimos nos exemplos acima.
Uma continue
só é possível dentro de um loop.
Cobrimos 3 tipos de loops:
while
– A condição é verificada antes de cada iteração.
do..while
– A condição é verificada após cada iteração.
for (;;)
– A condição é verificada antes de cada iteração, configurações adicionais disponíveis.
Para fazer um loop “infinito”, geralmente a construção while(true)
é usada. Tal loop, assim como qualquer outro, pode ser interrompido com a diretiva break
.
Se não quisermos fazer nada na iteração atual e quisermos avançar para a próxima, podemos usar a diretiva continue
.
break/continue
rótulos de suporte antes do loop. Um rótulo é a única maneira de break/continue
escapar de um loop aninhado para ir para um externo.
importância: 3
Qual é o último valor alertado por este código? Por que?
seja i = 3; enquanto (eu) { alerta( eu-- ); }
A resposta: 1
.
seja i = 3; enquanto (eu) { alerta( eu-- ); }
Cada iteração do loop diminui i
em 1
. A verificação while(i)
interrompe o loop quando i = 0
.
Portanto, as etapas do loop formam a seguinte sequência (“loop desenrolado”):
seja i = 3; alerta(eu--); // mostra 3, diminui i para 2 alert(i--) // mostra 2, diminui i para 1 alert(i--) // mostra 1, diminui i para 0 // pronto, while(i) check interrompe o loop
importância: 4
Para cada iteração do loop, anote o valor gerado e compare-o com a solução.
Ambos os loops alert
os mesmos valores ou não?
A forma do prefixo ++i
:
seja i = 0; enquanto (++i < 5) alerta(i);
A forma pós-fixada i++
seja i = 0; enquanto (i++ <5) alerta(i);
A tarefa demonstra como os formulários pós-fixados/prefixados podem levar a resultados diferentes quando usados em comparações.
De 1 a 4
seja i = 0; enquanto (++i < 5) alerta(i);
O primeiro valor é i = 1
, porque ++i
primeiro incrementa i
e depois retorna o novo valor. Portanto, a primeira comparação é 1 < 5
e o alert
mostra 1
.
Depois segue 2, 3, 4…
– os valores aparecem um após o outro. A comparação sempre utiliza o valor incrementado, pois ++
está antes da variável.
Finalmente, i = 4
é incrementado para 5
, a comparação while(5 < 5)
falha e o loop para. Portanto, 5
não é mostrado.
De 1 a 5
seja i = 0; enquanto (i++ <5) alerta(i);
O primeiro valor é novamente i = 1
. A forma postfix de i++
incrementa i
e então retorna o valor antigo , então a comparação i++ < 5
usará i = 0
(ao contrário de ++i < 5
).
Mas a chamada alert
é separada. É outra instrução que é executada após o incremento e a comparação. Então obtém a corrente i = 1
.
Então siga 2, 3, 4…
Vamos parar em i = 4
. A forma de prefixo ++i
aumentaria e usaria 5
na comparação. Mas aqui temos a forma postfix i++
. Portanto, aumenta i
para 5
, mas retorna o valor antigo. Portanto, a comparação é, na verdade, while(4 < 5)
– true, e o controle passa para alert
.
O valor i = 5
é o último, pois no próximo passo while(5 < 5)
é falso.
importância: 4
Para cada loop anote quais valores ele irá mostrar. Depois compare com a resposta.
Ambos os loops alert
os mesmos valores ou não?
A forma pós-fixada:
for (seja i = 0; i < 5; i++) alert( i );
A forma do prefixo:
for (seja i = 0; i < 5; ++i) alerta( i );
A resposta: de 0
a 4
em ambos os casos.
for (seja i = 0; i < 5; ++i) alerta( i ); for (seja i = 0; i < 5; i++) alert( i );
Isso pode ser facilmente deduzido do algoritmo de for
:
Execute uma vez i = 0
antes de tudo (início).
Verifique a condição i < 5
Se true
– execute o corpo do loop alert(i)
e então i++
O incremento i++
é separado da verificação de condição (2). Essa é apenas mais uma afirmação.
O valor retornado pelo incremento não é usado aqui, portanto não há diferença entre i++
e ++i
.
importância: 5
Use o loop for
para gerar números pares de 2
a 10
.
Execute a demonstração
para (seja i = 2; i <= 10; i++) { se (eu% 2 == 0) { alerta(eu); } }
Usamos o operador “módulo” %
para obter o restante e verificar a uniformidade aqui.
importância: 5
Reescreva o código alterando o loop for
para while
sem alterar seu comportamento (a saída deve permanecer a mesma).
for (seja i = 0; i < 3; i++) { alerta( `número ${i}!` ); }
seja i = 0; enquanto (eu <3) { alerta( `número ${i}!` ); eu++; }
importância: 5
Escreva um loop que solicite um número maior que 100
. Se o visitante inserir outro número, peça-lhe que insira novamente.
O loop deve solicitar um número até que o visitante insira um número maior que 100
ou cancele a entrada/insira uma linha vazia.
Aqui podemos assumir que o visitante apenas insere números. Não há necessidade de implementar um tratamento especial para uma entrada não numérica nesta tarefa.
Execute a demonstração
deixe num; fazer { num = prompt("Digite um número maior que 100?", 0); } enquanto (num <= 100 && num);
O loop do..while
se repete enquanto ambas as verificações são verdadeiras:
A verificação de num <= 100
– ou seja, o valor inserido ainda não é maior que 100
.
A verificação && num
é falsa quando num
é null
ou uma string vazia. Então o loop while
também para.
PS Se num
for null
então num <= 100
é true
, portanto, sem a segunda verificação, o loop não pararia se o usuário clicasse em CANCELAR. Ambas as verificações são necessárias.
importância: 3
Um número inteiro maior que 1
é chamado de primo se não puder ser dividido sem deixar resto por nada, exceto por 1
e por ele mesmo.
Em outras palavras, n > 1
é primo se não puder ser dividido igualmente por nada, exceto 1
e n
.
Por exemplo, 5
é primo porque não pode ser dividido sem resto por 2
, 3
e 4
.
Escreva o código que gera números primos no intervalo de 2
a n
.
Para n = 10
o resultado será 2,3,5,7
.
PS O código deve funcionar para qualquer n
, não ser ajustado para nenhum valor fixo.
Existem muitos algoritmos para esta tarefa.
Vamos usar um loop aninhado:
Para cada i no intervalo { verifique se eu tenho um divisor de 1..i se sim => o valor não é primo se não => o valor é primo, mostre-o }
O código usando um rótulo:
seja n = 10; próximoPrime: for (seja i = 2; i <= n; i++) { // para cada i... for (seja j = 2; j < i; j++) { // procura por um divisor.. if (i % j == 0) continue nextPrime; // não é primo, vá em seguida } alerta(eu); //um primo }
Há muito espaço para otimizá-lo. Por exemplo, poderíamos procurar os divisores de 2
até a raiz quadrada de i
. Mas de qualquer forma, se quisermos ser realmente eficientes para intervalos grandes, precisamos mudar a abordagem e confiar em matemática avançada e algoritmos complexos como peneira quadrática, peneira geral de campo numérico, etc.