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 == 3Declaraçã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 existeEm 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.