Laços (loops) de repetição são estruturas essênciais em praticamente todo algoritmo, e ter um bom domínio dessas estruturas é obrigatório para qualquer pessoa programadora.
Ultimamente, nos meus estudos de Javascript, descobri que esta linguagem não possui somente os laços de repetição comuns. Isso quer dizer que for
,while
e do-while
não são a única maneira de iterar sobre estruturas iteráveis e realizar repetições. E como já venho fazendo, se eu encontro algo interessante, resolvo escrever sobre.
Então, hoje vamos falar um pouco sobre os cinco tipos básicos de laços de repetição e sobre um método de objetos iteráveis que eu achei muito interessante. Vamos nessa!
For
Se você programa com certeza já conhece o laço for. Sua estrutura padrão é:
for(INICIALIZAÇÃO;CONDIÇÃO_DE_CONTINUIDADE;ALTERAÇÃO_DA_VARIAVEL_DE_CONTROLE){
codigo
}
Este tipo de laço geralmente é usado quando você quer uma quantidade finita e conhecida de repetições, embora ele também possa atuar como laço infinito se você mantiver a condição de continuidade ou a alteração de variável em branco.
Para usar esse laço, você precisa de uma variável para armazenar um valor que será testado a cada iteração do loop pela condição de continuidade. Essa variável pode ser delcarada dentro ou fora da inicialização do loop, porém é obrigatório que na inicialização do loop um valor seja atribuido a essa variável.
A condição de contuidade é geralmente uma condição relacional elaborada com a variável de controle, e enquanto esta condição for verdadeira, a variável é alterada de acordo com a especificação do usuário e o laço continua suas iterações. No momento em que esta condição é falsa, se sai do laço.
Por fim temos a parte da alteração da variável de controle, que pode ser tanto um incremento quanto um decremento a parte de incremento nada mais é do que a alteração da variável de controle.
While
O laço while também não é uma surpresa para pessoas que já possuem algum conhecimento de programação em outra linguagem. Sua estrutura padrão é:
while(CONDIÇÃO_DE_CONTINUIDADE){
codigo
}
Este tipo de laço geralmente é usado quando você não sabe a quantidade total de repetições que precisará iterar o código. É usual que a estrutura while
seja usada para ler um input do usuário, por exemplo, e continuar repetindo enquanto um valor determinado (como "x" para fechar a aplicação), não seja lido.
Esta estrutura também funciona com uma variável de controle que precisa ser criada fora do escopo do loop e incrementada dentro do escopo do mesmo, sendo que a condição de continuidade está também relacionada a esta variável de controle.
Vale lembrar também que é comum dizer que o laço while
possui de 0 a infinitas repetições, porque a condição de continuidade é sempre testada antes da execução do código, e se supormos que ela já não é atendida na primeira execução, o laço é terminado antes mesmo de executar o código.
Do-while
O laço do-while
também está presente em quase todas as linguagens de programação. Sua estrutura padrão é:
do{
codigo
}while(CONDIÇÃO_DE_CONTINUIDADE);
Este tipo de laço também é usado quando você não sabe a quantidade total de repetições que precisará iterar o código, e assim como no while
e no for
, a condição de continuidade deve estar relacionada a uma variável de controle. Esta variável deve ser declarada fora do escopo da estrutura e incrementada dentro do escopo.
Vale lembrar também que é comum dizer que o laço do-while
possui de 1 a infinitas repetições, porque a condição de continuidade é sempre testada ao final da execução do código, o que faz com que o código sempre seja executado ao menos uma vez, mesmo que a condição de continuidade seja falsa antes da entrada no loop.
For..in
Agora começamos a parte divertida que são as estruturas "extras" do Javascript. O for..in
é uma estrutura de repetição especial para a iteração de objetos. Ela itera sobre as propriedades(atributos) de um objeto, na ordem em que se apresentam no código, e sua estrutura básica é:
for(ATRIBUTO in OBJETO){
codigo
}
Atributo
, neste caso, é uma variável que pode ser declarada dentro da chamada do laço ou fora, e objeto
é o objeto sobre o qual queremos iterar. A utilização deste laço é bem simples, contanto que nos lembremos que um objeto é composto por vários membros, e que cada membro possui um nome e um valor.
Quando o laço começa, a variável atributo
recebe o nome do primeiro membro encontrado dentro do objeto, na próxima iteração, o conteúdo da variável atributo
é atualizado para o nome do segundo membro do objeto, e assim por diante enquanto houverem membros no objeto.
Para acessar os valores dos membros do objeto, é possível usar a notação de chaves, de modo que um código como o apresentado abaixo pode ser usado para imprimir todos os nomes e seus valores.
for(let att in obj){
console.log(`O membro ${att} tem valor ${obj[att]}`);
}
É importante salientar que embora esta estrutura possa iterar sobre arrays, esta pratica não é recomendada. Para este tipo de estruturas de dados, existe uma estrutura muito similar, o for..of
que veremos em seguida.
For..of
Se você entendeu como o for..in
funciona, a estrutura for..of
é bastante similar, porém ao invés de objetos, ela itera sobre objetos iterativos (arrays, sets, mapas, entre outros).
for(VALOR of ITERÁVEL){
codigo
}
valor
, neste caso, é uma variável que pode ser declarada dentro da chamada do laço ou fora, e iterável
é o objeto iterável (array, set ou mapa) sobre o qual queremos iterar.
Quando o laço começa, a variável valor
recebe o valor do primeiro elemento do objeto iterável, na próxima iteração, o conteúdo da variável valor
é atualizado para o valor do segundo elemento do objeto iterável, e assim por diante enquanto houverem elementos no objeto iterável.
E só para garantir que você sabe quais são os elementos dos objetos iteráveis:
- Vetores: um único número/caracter/string ou qualquer outra coisa que ocupe uma posição do vetor
- Sets: um único número/caracter/string ou qualquer outra coisa que ocupe uma posição do set
- Mapas: único par [chave, valor]
Com este laço, por exemplo, não precisamos conhecer a quantidade de elementos de um vetor para imprimí-lo.
for(let valor of vetor){
console.log(valor);
}
Apesar de este tipo de laço ser mais simples para imprimir o conteúdo de um objeto iterável, é importante lembrar que esta estrutura de repetição não guarda nenhum registro de qual posição do objeto iterável determinado valor ocupa, portanto é importante usá-lo com sabedoria.
forEach()
E para finalizar o artigo de hoje, trago a estrutura de repetição que mais me chamou a atenção do Javascript, o método forEach()
existente tanto na classe Array
quando na classe Map
. Esse método executa uma função em cada elemento do array ou do mapa. Vejamos com alguns exemplos como estes métodos funcionam.
Array.forEach()
Primeiro, vamor criar um array simples, e imaginar uma função que queremos que atue sobre cada um dos elementos.
const vetor = [-3,-2,-1,0,1,2,3,4];
function imprimeDobroPositivo(num){
if (num < 0){
num = Math.abs(num);
}
num *= 2;
console.log(num);
}
Bom, temos um vetor com números positivos e negativos, e uma função que vai transformar os números negativos em positivos, duplicar este valor e imprimir o valor duplicado.
Agora, vamos ao forEach()
. Primeiro, temos que saber que ela é um método da classe array, então será chamada no estilo vetor.forEach()
. Em segundo lugar, precisamos entender qual parâmetro passar para esta função. Nada mais do que a função que criamos anteriormente, mas sem os parênteses.
vetor.forEach(imprimeDobroPositivo);
A nossa callback function, a função que vamos chamar dentro do forEach()
pode ter até três parâmetros, sendo que pelo menos um deles (o elemento atual) é obrigatório. Este parâmetro não é especificado na chamada da função, mas sim na sua declaração. Na delcaração da função imprimeDobroPositivo
, temos um único parâmetro, que por padrão será associado ao elemento referente a iteração. Por isso, o código acima funciona.
Agora vamos falar sobre os outros dois parâmetros. Como precisamos alterar estes parâmetros na função de callback (no nosso caso imprimeDobroPositivo
), bastaria adicionar mais dois parâmetros. Por padrão, o segundo parâmetro será o índice do elemento, e o terceiro o próprio array. Vamor criar um novo exemplo então:
vetor = [1,2,3]
function imprimeBonito(numero,i,arr){
//quando esta função for chamada, numero (primeiro parâmetro) fará
//referência ao elemento da iteração, i (segundo parâmetro) fará
//referência ao índice do elemento e arr (terceiro parâmetro) é o
//próprio array.
console.log(`${numero} é o elemento na posição ${i} do vetor ${arr}`);
}
vetor.forEach(imprimeBonito);
O resultado deste trecho de código nada mais é do que:
1 é o elemento na posição 0 do vetor 1,2,3
2 é o elemento na posição 1 do vetor 1,2,3
3 é o elemento na posição 2 do vetor 1,2,3
Este tipo de iteração pode até não parecer grande coisa com os exemplos simples que utilizamos, mas se você precisar realizar grandes manipulações em elementos de arrays, com certeza o forEach()
pode ser muito útil para você.
Map.forEach()
Se você entendeu como o Array.forEach()
funciona, com certeza não vai ter problemas com este método. Assim como método anterior, este método é chamado no estilo map.forEach(função)
, e esta função também deve ter um parâmetro obrigatório (o valor do item da iteração), e pode ter como parâmetros opcionais a chave do elemento e o objeto map que está sendo iterado. Vamos criar um exemplo rápido com um mapa que armazenas pessoas e um id para essas pessoas.
pessoas = new Map ([[1,"Maria"],[2, "Antônio"],[3, "Angélica"]]);
function escreveNomeID(id, nome){
console.log(`${id} tem o id ${nome}`);
}
pessoas.forEach(escreveNomeID);
Confesso que não tenho muita experiencia com mapas, então não consigo imaginar um exemplo realmete útil com a utilização desta estrutura de dados, porém vocês podem comentar neste post algum exemplo que achem interessante.
E com isso, eu finalizo este artigo sobre estruturas (e métodos) de repetição em Javascript. Espero que este conteúdo possa ter sido útil para alguma coisa, e até a próxima.