Objeto: entender arrays JS e algumas funções de arrays
Principais termos técnicos abordados: html, JavaScript, map, join, function, let
Requisitos para as instruções funcionarem: editor de texto e navegador instalados
Requisitos para compreensão das instruções: noções bem básicas de HTML e JS
Como ler essa receita: instruções, dentro dos passos da receita e que requerem ação sua no computador, estarão escritas em cor azul. Comentários sobre os passos estarão em fonte normal, cor preta. Comandos, código-fonte, termos técnicos ou configuração explícita, estarão com fonte diferenciada.
A gente vai ver arrays e funções de repetição sobre arrays. É, array é a mesma coisa em tudo que é linguagem, uma coleção de dados.
Uma coleção de inteiros, uma coleção de strings, uma coleção de objetos...
E, como JS é um mundo selvagem, array também é uma coleção de gato e cachorro, você pode empurrar num mesmo array inteiro, string, objetos complexos, boleanos, não é exatamente a coisa mais linda do mundo, não é muito aconselhável, mas é possível.
Uma coisa boa, ao menos, é que dificilmente a gente vai precisar escrever um comando de repetição (for, while, do/while), porque os arrays em JS já vêm equipados com funções de repetição que cobrem a imensa maioria das coisas que a gente precisa fazer com repetições. Na verdade, você terá que se esforçar muito para descobrir algo que não dê para fazer com as funções de repetição pré-definidas nos arrays JS. Para usar essas funções de repetição você precisa entender que as funções JS podem ser usadas como variáveis, e se você não entende isso, trate de entender seguindo receita anterior a essa.
Mas, resumindo, escrever um for, hoje em dia, pode sero mesmo que pagar de programador velho.
Ou desatualizado.
Ou ambos.
Não dá pra essa receita rejuvenescer ninguém.
Mas dá pra atualizar.
Abra o editor e salve o seguinte código como index.html.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<div id="meu amor"><button id="botaoCarregar">Carregando cervejas...</button></div>
</body>
<script>
function carregarDiv(){
let div = document.getElementById("meu amor")
div.innerHTML = `<h1>Guinness</h1>`
}
let botao = document.getElementById("botaoCarregar")
botao.addEventListener("click", carregarDiv)
</script>
</html>
Esse é um código que já foi trabalhado em outra receita, espero que soe familiar.
Agora, vamos alterá-lo sutilmente, para que exiba alguns nomes de cerveja em vez de um nome de cerveja. Afinal, a mensagem inicial é no plural, "Carregando cervejas"...
Altere o código para o seguinte:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<div id="meu amor"><button id="botaoCarregar">Carregando cervejas...</button></div>
</body>
<script>
let cervejas = ["Guiness", "Desperados", "Becks"]
function carregarDiv(){
let div = document.getElementById("meu amor")
div.innerHTML = `<h1>${cervejas}</h1>`
}
let botao = document.getElementById("botaoCarregar")
botao.addEventListener("click", carregarDiv)
</script>
</html>
Abrindo pelo navegador você deve ver algo como...
Mas vamos entender o código.
Primeiro a gente botou um let antes e fora da função carregarDiv, declarando uma variável cervejas.
let cervejas = ["Guiness", "Desperados", "Becks"]
Primeiro, dá pra ver que isso é um array, né? Um array de 3 strings. Essa é a forma mais simples de fazer um array.
Segundo, declarando ali fora, essa variável vai estar visível também dentro da função carregarDiv. Dava pra declarar dentro da própria função, pois o array só é usado lá, por enquanto, mas a gente pretende ir buscar essas informações fora da nossa página mais adiante, em outras receitas e, nesse caso, nossa função ficaria com as responsabilidades de ir buscar informações e de fazer interface com o usuário. Acredite, a gente não quer isso.
Terceiro, há outras formas de se declarar e acrescentar elementos ao final de um array em JS. Aqui vai um deles:
let cervejas = new Array()
cervejas.push("Guiness")
cervejas.push("Desperados")
cervejas.push("Becks")
Essas 4 linhas teriam o mesmo efeito daquela que escrevemos. Faça o que você achar mais bonito. Eu faria o mais simples.
Outra novidade é lá dentro da função carregarDiv, na atribuição...
div.innerHTML = `<h1>${cervejas}</h1>`
Pra que serve esse 'dólar'? Pra injetar, em strings, valores de quaisquer variáveis visíveis quando da execução da instrução. E cervejas é uma variável visível naquele ponto.
Mas o string precisa ser declarado entre acentos graves! Não esqueça disso! Não é aspa simples, não são aspas duplas, é acento grave, aquele mesmo que, em língua portuguesa, você não acerta nunca.
- E de onde vêm aquelas vírgulas que aparecem na página, entre os nomes das cervejas, professor? A gente não botou nenhuma vírgula no array...
De fato, não. É que o vetor cervejas vai ser transformado num string quando a gente usar o dólar. E o comportamento default de transformar array em um string é transformar cada um de seus itens em string e separá-los por vírgula, que é o que está sendo feito.
- Mas e se eu quiser separar por outra coisa?
Você pode usar uma função de repetição...
Altere o código para que fique como a seguir.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<div id="meu amor"><button id="botaoCarregar">Carregando cervejas...</button></div>
</body>
<script>
let cervejas = ["Guiness", "Desperados", "Becks"]
function carregarDiv(){
let div = document.getElementById("meu amor")
div.innerHTML = `<h1>${cervejas.join("--")}</h1>`
}
let botao = document.getElementById("botaoCarregar")
botao.addEventListener("click", carregarDiv)
</script>
</html>
Carregando a página e clicando no botão, você deve ver o seguinte...
No código, mudamos apenas a linha...
div.innerHTML = `<h1>${cervejas.join("--")}</h1>`
Ou seja, em vez de injetarmos no string a conversão default do array cervejas em string, a gente tá injetando o string resultante da chamada ao método join, que todo array JavaScript tem. Porque array em JavaScript é objeto, pode ter, e tem, nesse caso, informação e comportamento dentro de si.
- E o que faz esse tal join que tem em todo objeto array no JS?
Bem, ele transforma o array num string só, mas deixa você passar o delimitador que você bem entender como parâmetro. Nesse caso, estamos passando 'dois tracinhos', mas modifique isso e veja os efeitos na execução.
Há outras funções legais também, vamos ver uma delas.
Imagine que a gente queira transformar cada nome de cerveja numa marca h1 específica, tipo que o html final a ser empurrado no div.innerHTML ficasse algo como...
<h1>Guiness</h1>
<h1>Desperados</h1>
<h1>Becks</h1>
O join, sozinho, não resolveria.
Vamos a uma solução ruim primeiro. Modifique, salve e recarregue, de toda forma.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<div id="meu amor"><button id="botaoCarregar">Carregando cervejas...</button></div>
</body>
<script>
let cervejas = ["Guiness", "Desperados", "Becks"]
function carregarDiv(){
let div = document.getElementById("meu amor")
let cervejasHtml = [`<h1>${cervejas[0]}</h1>`,`<h1>${cervejas[1]}</h1>`, `<h1>${cervejas[2]}</h1>`]
div.innerHTML = `${cervejasHtml.join("\n")}`
}
let botao = document.getElementById("botaoCarregar")
botao.addEventListener("click", carregarDiv)
</script>
</html>
Ora, ora, ao recarregar e clicar no botão a gente vê o que a gente quer...
E inspecionando o código html dentro do div "meu amor" é exatamente o que a gente quer também...
A gente, basicamente, criou uma nova variável local...
let cervejasHtml = [`<h1>${cervejas[0]}</h1>`,`<h1>${cervejas[1]}</h1>`, `<h1>${cervejas[2]}</h1>`]
... que é um array cujos itens são strings com a marca h1 e o nome de uma cerveja dentro.
Depois fizemos um join no array de marcas em vez de no array de nomes de cervejas, botando um 'pula linha' como delimitador
div.innerHTML = `${cervejasHtml.join("\n")}`
Com a parte do join até que tá tudo bem.
No entanto, o que incomoda é aquela linhazinha sebosa antes do join...
let cervejasHtml = [`<h1>${cervejas[0]}</h1>`,`<h1>${cervejas[1]}</h1>`, `<h1>${cervejas[2]}</h1>`]
A gente, basicamente, criou um array de strings (contendo marcas h1) com base num array de nomes. Mas a gente fez isso indexando cada um dos elementos 'na tora'. Se a gente modificar o array cervejas pra ter 10 elementos, a nossa função continuaria gerando um html com 3 marcas h1, a menos que a gente se propusesse refazer o cervejasHtml, referenciando todos os 10 itens, e isso é algo que eu, particularmente, não vou fazer.
Porque seria estúpido, é CLARO que é esse negócio é coisa que se resolva com repetição, mas vai 1 real e 99 além disso.
A gente precisa perceber que está criando um array, o cervejasHtml, com base em outro array, o cervejas.
A gente precisa perceber que o array resultante, cervejasHtml, deve ter o mesmo tamanho do array original, cervejas.
A gente precisa perceber que um elemento qualquer na posição i do vetor resultante é construído tão somente com base no elemento i do vetor original.
Essa transformação, de um item em outro item, é tão besta que a gente poderia até escrever uma função para ela, certo? Algo assim...
function transformar(item){
return `<h1>${item}</h1>`
}
Pois é, acontece que a operação de criar um array com base em outro é extremamente comum, e a única coisa que não se pode prever nessa operação extremamente comum é justamente como a gente quer que um elemento de um vetor seja transformado num elemento do outro vetor.
A única coisa que a gente não pode prever é justamente o que nossa funçãozinha transformar faz.
E o JS oferece um método de repetição que faz essa criação de um novo array com base em outro. É o método map.
Modifique o código para que fique como a seguir. Salve e recarregue a página.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<div id="meu amor"><button id="botaoCarregar">Carregando cervejas...</button></div>
</body>
<script>
let cervejas = ["Guiness", "Desperados", "Becks"]
function transformar(item){
return `<h1>${item}</h1>`
}
function carregarDiv(){
let div = document.getElementById("meu amor")
//let cervejasHtml = [`<h1>${cervejas[0]}</h1>`,`<h1>${cervejas[1]}</h1>`, `<h1>${cervejas[2]}</h1>`]
let cervejasHtml = cervejas.map(transformar)
div.innerHTML = `${cervejasHtml.join("\n")}`
}
let botao = document.getElementById("botaoCarregar")
botao.addEventListener("click", carregarDiv)
</script>
</html>
Pronto, em vez daquela linha sebosa, que deixei como comentário, a título de comparação, escrevemos nossa funçãozinha transformar e executamos, dentro do carregarDiv, a linha
let cervejasHtml = cervejas.map(transformar)
Ou seja, ao chamarmos a função map, não estamos chamando a função transformar, estamos passando-a como parâmetro, como se fosse uma variável, coisa que no JS é corriqueira e que já estudamos. Quem vai chamar a função transformar é a própria função map, quando estiver executando o algoritmo de criar um novo array a partir de um array existente. Isso nos economiza um laço e algumas atribuições, porque quem faz isso é a função map.
Assim, o array original é o cervejas, o vetor sobre o qual a gente invoca o map.
E o array resultante, o novo array, é o array retornado pela função map.
O array original permanece como está.
E a função transformar é uma callback function - uma função que você escreve, mas não chama, não invoca.
Quem invoca, nesse caso, é o método map, da classe Array. Poderia ser uma função que você mesmo escreveu, ou algum outro método de algum outro tipo. O que faz ela ser uma callback function, nesse cenário, é o fato de que está sendo passada como parâmetro sem ser invocada, como se fosse uma variável, para ser invocada por quem a recebeu como parâmetro.
Métodos básicos dos arrays - incuindo push() e join()
Métodos de repetição dos arrays, incluindo o map()
Faça com que as cervejas fiquem dentro de marcas div e não dentro de marcas h1
Estilize as marcas div que contêm os nomes das cervejas
Transforme os nomes das cervejas numa tabela (<table>) estilizada em vez de em uma sequência de divs
Crie um botão mostrar cervejas ordenadas, que ordena o array cervejas. Pesquise como ordenar vetores em JS. Não impemente você mesmo nenhum método de ordenação. Depois de ordenar o array, faça a transformação em html e exiba no div "meu amor" (como tabela ou sequencia de divs)
Crie um botão para "embaralhar" os nomes das cervejas, deixando-os numa ordem arbitrária a cada clique. Não implemente algoritmo de embaralhamento. Seja perspicaz e confira os métodos do tipo Array. Alguém já deve ter feito isso.