Objeto: constantes, funções de callback e arrow functions
Principais termos técnicos abordados: html, JavaScript, arrow function, callback function, refatoração, map, const, 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 ter implementado receita anterior
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.
"Se queremos que tudo continue como está, é preciso que tudo mude".
Aqui vamos aprender a, basicamente, escrever funções de uma forma diferente.
Vamos partir do final de receita anterior, sobre funções e arrays.
E, na verdade, não vamos chegar a lugar nenhum em termos de funcionalidade. Vamos apenas reescrever algumas coisas e fazer o que já fizemos.
O nome disso é refatoração, e a gente vai fazer apenas para aprender o conceito de "arrow function" e dar uma reforçada no conceito de "callback function".
Mas, na prática, quando se realiza esse procedimento em ambiente de desenvolvimento, o tal refatoramento tem grandes, grandes ambições.
Porque software é como a decadente nobreza italiana de meados do século XIX, nobreza sobre a qual escreveu Lampedusa no romance "O Leopardo" - "se queremos que tudo continue como está, é preciso que tudo mude".
A refatoração, claro, não está preocupada em manter o status de nenhuma classe dominante. Pretende que se mudem "as coisas" - o código - para que o desenvolvimento de software continue caminhando, continue "como está". Ou para que melhore, mas não tenha grandes esperanças nisso.
Um real e 99 de cultura e engenharia de software à parte, vamos "refatorar" um código na ambição bem menos pretensiosa de aprender e escrever funções JS de uma forma mais "moderninha".
Edite e salve um arquivo index.html com o seguinte conteúdo.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<div><button id="botaoCarregar">Carregando cervejas...</button></div>
<div id="meu amor"></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 = cervejas.map(transformar)
div.innerHTML = `${cervejasHtml.join("\n")}`
}
let botao = document.getElementById("botaoCarregar")
botao.addEventListener("click", carregarDiv)
</script>
</html>
Eu sei, já faz bem 3 textos que a gente identifica esse div por meu amor. Você pode "refatorar" isso também, se quiser, mas temos coisas mais importantes a fazer.
Primeiramente, a gente precisa aprender a declarar constantes.
Não há muito segredo com constantes em JS. São "variáveis" às quais você deve atribuir valor logo na declaração e que não pode fazer isso (atribuir) mais nunca enquanto a constante viver.
A gente pode tornar as variáveis locais da função carregarDiv constantes. Elas nunca mudam e tampouco devem mudar dentro do escopo daquela função. Lembre que, a cada chamada, o escopo local é refeito.
Modifique as variáveis locais da função carregarDiv e deixe-as como constantes.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<div><button id="botaoCarregar">Carregando cervejas...</button></div>
<div id="meu amor"></div>
</body>
<script>
let cervejas = ["Guiness", "Desperados", "Becks"]
function transformar(item){
return `<h1>${item}</h1>`
}
function carregarDiv(){
const div = document.getElementById("meu amor")
const cervejasHtml = cervejas.map(transformar)
div.innerHTML = `${cervejasHtml.join("\n")}`
}
let botao = document.getElementById("botaoCarregar")
botao.addEventListener("click", carregarDiv)
</script>
</html>
Salve, carregue a página e clique no botão, se quiser. Você deve var algo assim após o clique.
A gente poderia declarar todas as variáveis deste código como constantes, não daria nenhum erro.
Mas há outra coisa mais interessante para declararmos como constantes.
As funções.
É, jovem, nada mais constante que essas funções. Não mudam nunca, ninguém nunca atribui nada a elas a não ser a própria definição, que é feita uma vez só.
Ou seja, são constantes.
Modifique o código da função carregarDiv.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<div><button id="botaoCarregar">Carregando cervejas...</button></div>
<div id="meu amor"></div>
</body>
<script>
let cervejas = ["Guiness", "Desperados", "Becks"]
function transformar(item){
return `<h1>${item}</h1>`
}
//function carregar(){
const carregarDiv = () => {
const div = document.getElementById("meu amor")
const cervejasHtml = cervejas.map(transformar)
div.innerHTML = `${cervejasHtml.join("\n")}`
}
let botao = document.getElementById("botaoCarregar")
botao.addEventListener("click", carregarDiv)
</script>
</html>
Pronto. Em destaque, declaramos nossa função como uma constante. Deixei o "jeito antigo" comentado no código para facilitar a comparação entre as abordagens.
Basicamente, usamos a palavra chave const seguida do nome da função e do símbolo de atribuição. Sempre que você declarar uma constante o nome dela deve ser seguido de uma atribuição. Claro, você poderia declarar com um let também, mas nesse caso faz mais sentido o const - é uma função e não temos interesse de fazer mais de uma atribuição a esse identificador carregarDiv.
Depois do símbolo de atribuição, listamos os atributos, entre parenteses, da mesma forma que faríamos na delcaração convencional. Como não há parâmetros aqui, usamos apenas o ().
Depois disso escrevemos uma 'seta', do inglês arrow, denotada pelos símbolos =>.
Funções JS declaradas com a listagem de parâmetros e o corpo separados por => são chamadas de arrow functions.
E depois do => é tudo do mesmo jeito. Parece muito barulho por nada, parece até mais fácil o jeito antigo, mas daqui a pouco a gente vê a coisa ficar mais interessante.
Porque as arrow functions são bastante utilizadas como callback functions, aquelas funções que são passadas como parâmetro para alguma outra função/método (como o map do Array) em vez de serem chamadas convencionalmente.
- Ah, professor, a função transformar é uma cóubéqui fúnchion, né não?
Ora, ora, temos um Sherlock Holmes aqui...
Modifique o código da função transformar.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<div><button id="botaoCarregar">Carregando cervejas...</button></div>
<div id="meu amor"></div>
</body>
<script>
let cervejas = ["Guiness", "Desperados", "Becks"]
const transformar = (item) => {
return `<h1>${item}</h1>`
}
//function carregar(){
const carregarDiv = () => {
const div = document.getElementById("meu amor")
const cervejasHtml = cervejas.map(transformar)
div.innerHTML = `${cervejasHtml.join("\n")}`
}
let botao = document.getElementById("botaoCarregar")
botao.addEventListener("click", carregarDiv)
</script>
</html>
- Continua meio sem futuro, professor...
Calma. Dá pra gente tirar os parênteses da listagem de marâmetros, pois nesse caso tem apenas um. E é só nesse caso que podemos fazer isso.
Assim...
const transformar = (item) => {
return `<h1>${item}</h1>`
}
... pode virar...
const transformar = item => {
return `<h1>${item}</h1>`
}
- Vantagem da porra, professor... economizou 2 caracteres...
Calma que o Brasil é nosso. Como a função só tem uma linha e essa linha é um return, a gente pode omitir o abre/fecha chaves e o próprio nome return desde que escrevamos tudo numa única linha.
Assim...
const transformar = item => {
return `<h1>${item}</h1>`
}
... ficaria...
const transformar = item => `<h1>${item}</h1>`
- Agora sim... tá começando a dar frio na barriga.
Pois é. E como essa função transformar só é usada para ser passada como parâmetro pro método map, na verdade a função transformar não precisa nem ser declarada como constante e nem precisa de um nome. É só pegar a definição dela, o que vem depois do sinal de atribuição...
item => `<h1>${item}</h1>`
... e passar direto como parâmetro para o map
const cervejasHtml = cervejas.map( item => `<h1>${item}</h1>` )
O código completo ficaria como abaixo.
Modifique-o, salve-o, teste-o.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<div><button id="botaoCarregar">Carregando cervejas...</button></div>
<div id="meu amor"></div>
</body>
<script>
let cervejas = ["Guiness", "Desperados", "Becks"]
//function carregar(){
const carregarDiv = () => {
const div = document.getElementById("meu amor")
const cervejasHtml = cervejas.map( item => `<h1>${item}</h1>` )
div.innerHTML = `${cervejasHtml.join("\n")}`
}
let botao = document.getElementById("botaoCarregar")
botao.addEventListener("click", carregarDiv)
</script>
</html>
Compreenda e acostume-se com essa notação, com essa forma de escrever funções, ela é bastante comum.
Nesse caso da função que passamos para o cervejas.map, ela é uma arrow function, pois é definida com símbolo => posto entre parâmetros e corpo. Ela é também, naquele ponto, uma callback function, uma vez que não está sendo invocada diretamente, mas passada "como variável" para ser invocada oportunamente pelo método que a recebe como parâmetro - o cervejas.map. E, por fim, ela é também uma função anônima. Não tem nome, caso você ainda não tenha percebido. Quem a recebe como parâmetro lhe dá um nome na declaração do método e está tudo certo, mas nós que a definimos não a 'batizamos'.
Há quem chame essas funções de lambda functions, ou a expressão como um todo - item => `<h1>${item}</h1>` - de lambda expression.
No mundo JS, eu leio mais o termo arrow function.
Arrow functions, texto 'protocolar' 1
Arrow functions, texto 'protocolar' 2
Vídeo sobre arrow functions.
Callback functions - bom material com texto e vídeo, mas sem a mesma emoção desta receita.
Faça mais uma refatoração. Modifique a função carregarDiv do modo que ela receba um parâmetro, identificado por cervs. Esse parâmetro é um vetor e a chamada ao método map, dentro da função carregarDiv, deve ser feita sobre o parâmetro cervs e não sobre a variável (global) cervejas. Faça as alterações necessárias para que o array cervejas seja passado como parâmetro para o carregarDiv e a página contunue com o mesmo comportamento.
Você deve fazer todos os exercícios da receita anterior, modificando o array de cervejas para algum domínio que você acha mais interessante - roupa, sorvete, cachaça, o que você quiser. Todas as funções que você escrever devem ser arrow functions. Todas.
Troque todos os botões dos exercícios anteriores e transforme-os em links, fazendo com que os links chamem os métodos adequados da mesma forma que os botões chamam.