b
JavaScript
Teremos, durante o curso, o objetivo e a necessidade de aprender certa quantidade de JavaScript, além de desenvolvimento web.
JavaScript evoluiu rapidamente nos últimos anos e, neste curso, usamos as funcionalidades das versões mais recentes. O nome oficial do padrão de JavaScript é ECMAScript. Atualmente, a versão mais recente é a lançada em junho de 2022 com o nome de ECMAScript®2022, também conhecido como ES13.
Os navegadores ainda não suportam todas as funcionalidades mais recentes de JavaScript e devido a esse fato, muito código executado em navegadores é transpilado de uma versão mais recente de JavaScript para uma versão mais antiga e compatível.
Hoje em dia, a maneira mais popular de fazer a transpilação é usando o transcompilador Babel. A transpilação é configurada automaticamente em aplicações React criadas com create-react-app. Vamos olhar mais de perto a configuração de transpilação na Parte 7 deste curso.
Node.js é um ambiente de tempo de execução JavaScript baseado no motor JavaScript Chrome V8 da Google e funciona praticamente em qualquer lugar, desde servidores até telefones celulares. Vamos praticar a escrita de código JavaScript usando Node. As versões mais recentes do Node são compatíveis com as versões mais recentes de JavaScript, então o código não precisa ser transpilado.
O código é escrito em arquivos com extensão .js que são executados ao emitir o comando node nome_do_arquivo.js
Também é possível escrever código JavaScript na console do Node.js, que pode ser aberta digitando "node" na linha de comando, bem como na aba Console nas Ferramentas do Desenvolvedor do navegador. As revisões mais recentes do Chrome lidam bem com as novas funcionalidades de JavaScript sem precisar transpilar o código. Alternativamente, você pode usar uma ferramenta como JS Bin.
JavaScript lembra mais ou menos o Java, tanto no nome quanto na sintaxe. Porém, quando se trata do mecanismo central da linguagem, eles não poderiam ser mais diferentes. Da perspectiva de alguém que vem de um background em Java, a forma como JavaScript se comporta pode parecer um pouco estranho, principalmente se não for feito algum esforço para entender suas características.
Em determinados círculos, tem se popularizado tentar "simular" funcionalidades e padrões de design de Java em JavaScript. Não recomendamos fazer isso, já que as linguagens e seus respectivos ecossistemas são, no final das contas, muito diferentes.
Variáveis
Em JavaScript, existem algumas maneiras de definir variáveis:
const x = 1
let y = 5
console.log(x, y) // 1, 5 são impressos
y += 10
console.log(x, y) // 1, 15 são impressos
y = 'algum texto'
console.log(x, y) // 1, algum texto são impressos
x = 4 // causará um erro
const não define uma variável, mas uma constante no qual o valor não pode mais ser alterado. Por outro lado, let define uma variável padrão.
No exemplo acima, também vemos que o tipo de dados da variável pode mudar durante a execução. No início, y armazena um inteiro; no final, armazena uma string.
Também é possível definir variáveis em JavaScript usando a palavra-chave var, que foi, por muito tempo, a única maneira de definir variáveis. const e let foram adicionadas recentemente na versão ES6. Em situações específicas, var funciona de maneira diferente em comparação com as definições de variáveis na maioria das linguagens. Visite JavaScript Variables - Should You Use let, var or const? on Medium ou Keyword: var vs. let on JS Tips para mais informações. Durante este curso, o uso de var não é recomendado, devendo-se privilegiar const e let! Você pode ver mais sobre este assunto no YouTube, por exemplo, var, let and const - ES6 JavaScript Features
Arrays
Um array e alguns exemplos de seu uso:
const t = [1, -1, 3]
t.push(5)
console.log(t.length) // 4 é impresso
console.log(t[1]) // -1 é impresso
t.forEach(value => {
console.log(value) // os números 1, -1, 3, 5 são impressos, cada um em sua própria linha
})
O importante neste exemplo é o fato de que o conteúdo do array pode ser modificado mesmo que seja definido como uma const. Por conta do array ser um objeto, a variável sempre aponta para o mesmo objeto. No entanto, o conteúdo do array muda à medida que novos itens são adicionados a ele.
Uma forma de iterar através dos itens do array é usando forEach, como visto no exemplo. forEach recebe uma função definida usando a sintaxe de seta como parâmetro.
value => {
console.log(value)
}
forEach chama a função para cada um dos itens no array, sempre passando o item individual como argumento. A função como argumento de forEach também pode receber outros argumentos.
No exemplo anterior, um novo item foi adicionado ao array usando o método push. Quando se usa React, técnicas de programação funcional são comumente usadas. Uma característica do paradigma de programação funcional é o uso de estruturas de dados imutáveis. No código React, é preferível usar o método concat, que não adiciona o item ao array, mas cria um array novo no qual o conteúdo do antigo array e o novo item são ambos incluídos.
const t = [1, -1, 3]
const t2 = t.concat(5)
console.log(t) // [1, -1, 3] é impresso
console.log(t2) // [1, -1, 3, 5] é impresso
A chamada de método t.concat(5) não adiciona um novo item ao array antigo, mas retorna um array novo que, além de conter os itens do array antigo, também contém o novo item.
Há muitos métodos úteis definidos para arrays. Vamos dar uma olhada em um pequeno exemplo de uso do método map.
const t = [1, 2, 3]
const m1 = t.map(valor => valor * 2)
console.log(m1) // [2, 4, 6] é impresso
Com base no array antigo, o map cria um array novo, para o qual a função dada como parâmetro é usada para criar os itens. No caso deste exemplo, o valor original é multiplicado por dois.
O map também pode transformar o array em algo completamente diferente:
const m2 = t.map(valor => '<li>' + valor + '</li>')
console.log(m2)
// [ '<li>1</li>', '<li>2</li>', '<li>3</li>' ] é impresso
Aqui, um array preenchido com valores inteiros é transformado em um array contendo strings de HTML usando o método map. Na parte 2 deste curso, veremos que o map é usado com frequência em React.
Itens individuais de um array são fáceis de atribuir a variáveis com a ajuda da atribuição via desestruturação (destructuring assignment).
const t = [1, 2, 3, 4, 5]
const [primeiro, segundo, ...resto] = t
console.log(primeiro, segundo) // 1, 2 é impresso
console.log(resto) // [3, 4, 5] é impresso
Graças à atribuição, as variáveis primeiro e segundo receberão os dois primeiros inteiros do array como seus valores. Os inteiros restantes são "coletados" em um array próprio que é então atribuído à variável resto.
Objetos
Existem algumas formas diferentes de se definir objetos em JavaScript. Um método muito comum é usar objetos literais (object literals), que ocorre listando suas propriedades dentro de chaves:
const objeto1 = {
nome: 'Arto Hellas',
idade: 35,
educacao: 'PhD',
}
const objeto2 = {
nome: 'Desenvolvimento de aplicações web Full Stack',
nivel: 'Estudos intermediários',
tamanho: 5,
}
const objeto3 = {
nome: {
primeiro: 'Dan',
ultimo: 'Abramov',
},
notas: [2, 3, 5, 3],
departamento: 'Universidade Stanford',
}
Os valores das propriedades podem ser de qualquer tipo, como inteiros, strings, arrays, objetos...
As propriedades de um objeto são referenciadas usando a notação de "ponto", ou usando colchetes:
console.log(objeto1.nome) // Arto Hellas é impresso
const nomePropriedade = 'idade'
console.log(objeto1[nomePropriedade]) // 35 é impresso
Você também pode adicionar propriedades a um objeto em tempo de execução usando a notação de ponto ou colchetes:
objeto1.endereco = 'Helsinque' // *endereço
objeto1['numero secreto'] = 12341
A última adição representada acima tem que ser feita usando colchetes porque, quando se usa a notação de ponto, numero secreto não é um nome de propriedade válido devido ao caractere de espaço separando as duas palavras.
Naturalmente, os objetos em JavaScript também podem ter métodos. No entanto, durante este curso, não precisaremos definir objetos com métodos próprios. É por isso que eles só são discutidos rapidamente durante o curso.
Objetos também podem ser definidos usando funções construtoras, o que resulta em um mecanismo semelhante a muitas outras linguagens de programação, como Java. Apesar desta semelhança, o JavaScript não tem classes tal qual outras linguagens de programação orientadas a objetos. No entanto, a partir da versão ES6, foi adicionada a sintaxe para classes, o que em alguns casos ajuda a estruturar classes orientadas a objetos.
Funções
Já nos familiarizamos com a definição de arrow functions (funções de seta). O processo completo, sem atalhos, para definir uma arrow function é o seguinte:
const soma = (p1, p2) => {
console.log(p1)
console.log(p2)
return p1 + p2
}
E a função é chamada:
const resultado = soma(1, 5)
console.log(resultado)
Se houver apenas um parâmetro, podemos excluir os parênteses da definição:
const quadrado = p => {
console.log(p)
return p * p
}
Se a função contiver apenas uma expressão, então as chaves não são necessárias. Neste caso, a função retorna apenas o resultado de sua única expressão. Agora, se removermos a impressão do console, podemos encurtar ainda mais a definição da função:
const quadrado = p => p * p
Este formato é particularmente útil ao manipular arrays, como quando usamos o método "map":
const t = [1, 2, 3]
const tAoQuadrado = t.map(p => p * p)
// tAoQuadrado agora é [1, 4, 9]
A funcionalidade da arrow function foi adicionada ao JavaScript há apenas alguns anos, com a versão ES6. Antes disso, a única maneira de definir funções era usando a palavra-chave function.
Existem duas maneiras de se referenciar uma função; uma é atribuir um nome em uma declaração de função (function declaration).
function produto(a, b) {
return a * b
}
const resultado = produto(2, 6)
// resultado agora é 12
Outra maneira de definir uma função é usando uma expressão de função (function expression). Neste caso, não é necessário atribuir um nome à função, e a definição pode residir dentro do restante do código:
const media = function(a, b) { // *média
return (a + b) / 2
}
const resultado = media(2, 5)
// resultado agora é 3.5
Durante este curso, todas as funções serão definidas usando a sintaxe de seta.
Métodos de objetos e "this"
Como este curso usa uma versão de React que contém React Hooks, não é necessário definir objetos com métodos. O conteúdo deste capítulo não é relevante para o curso, mas certamente é bom conhecer. Em particular, ao usar versões antigas de React, é necessário compreender os tópicos deste capítulo.
Arrow functions e funções definidas usando a palavra-chave function variam substancialmente em relação ao comportamento da palavra-chave this, que se refere ao próprio objeto.
Podemos atribuir métodos a um objeto definindo propriedades que são funções:
const arto = {
nome: 'Arto Hellas',
idade: 35,
educacao: 'PhD', // *educação
cumprimentar: function() { // *saudação console.log('olá, meu nome é ' + this.nome) },}
arto.cumprimentar() // "olá, meu nome é Arto Hellas" é impresso
Métodos podem ser atribuídos a objetos mesmo após a criação do objeto:
const arto = {
nome: 'Arto Hellas',
idade: 35,
educacao: 'PhD',
cumprimentar: function() {
console.log('olá, meu nome é ' + this.nome)
},
}
arto.envelhecer = function() { this.idade += 1}
console.log(arto.idade) // 35 é impresso
arto.envelhecer()
console.log(arto.idade) // 36 é impresso
Vamos modificar um pouco o objeto:
const arto = {
nome: 'Arto Hellas',
idade: 35,
educacao: 'PhD',
cumprimentar: function() {
console.log('olá, meu nome é ' + this.nome)
},
fazerAdicao: function(a, b) { // *fazerAdição console.log(a + b) },}
arto.fazerAdicao(1, 4) // 5 é impresso
const referenciaParaAdicao = arto.fazerAdicao
referenciaParaAdicao(10, 15) // 25 é impresso
Agora, o objeto tem o método fazerAdicao, que calcula a soma dos números dados a ele como parâmetros. O método é chamado da maneira tradicional, usando o objeto arto.fazerAdicao(1, 4) ou armazenando uma referência ao método em uma variável e chamando o método através da variável: referenciaParaAdicao(10, 15).
Se tentarmos fazer o mesmo com o método cumprimentar, deparamo-nos com um problema:
arto.cumprimentar() // "olá, meu nome é Arto Hellas" é impresso
const referenciaParaCumprimentar = arto.cumprimentar
referenciaParaCumprimentar() // "olá, meu nome é undefined" é impresso
Ao chamar o método através de uma referência, o método perde o conhecimento do que era o this original. Ao contrário de outras linguagens, em JavaScript, o valor de this é definido com base em como o método é chamado. Ao chamar o método através de uma referência, o valor de this se torna o chamado objeto global (global object) e o resultado final sai geralmente diferente do que o desenvolvedor originalmente pretendeu.
Perder o rastro do this ao escrever código JavaScript traz alguns problemas eventuais. Algumas situações frequentemente surgem onde React ou o Node (ou mais especificamente o motor JavaScript do navegador) precisa chamar algum método em um objeto que o desenvolvedor tenha definido. No entanto, neste curso, evitamos esses problemas usando o JavaScript "sem this".
Uma situação que leva ao "desaparecimento" do this ocorre quando definimos um tempo limite para chamar a função cumprimentar no objeto arto, usando a função setTimeout.
const arto = {
nome: 'Arto Hellas',
cumprimentar: function() {
console.log('olá, meu nome é ' + this.nome)
},
}
setTimeout(arto.cumprimentar, 1000)
Como mencionado, o valor de this em JavaScript é definido com base na forma como o método é chamado. Quando o setTimeout está chamando o método, é o motor JavaScript que realmente chama o método e, nesse ponto, this se refere ao objeto global.
Existem vários mecanismos pelos quais o this original pode ser preservado. Um desses é usando um método chamado bind (significa amarrar ou atar):
setTimeout(arto.cumprimentar.bind(arto), 1000)
Chamar arto.cumprimentar.bind(arto) cria uma nova função onde this é obrigado a apontar para Arto, independentemente de onde e como o método está sendo chamado.
Usando Arrow functions é possível resolver alguns dos problemas relacionados ao this. No entanto, eles não devem ser usados como métodos para objetos, pois o this não funciona de forma alguma. Mais tarde, voltaremos a discutir o comportamento da palavra-chave this em relação às arrow functions.
Se deseja compreender de fato como this funciona em JavaScript, a Internet está cheia de material sobre o assunto como, por exemplo, a série screencast Understand JavaScript's this Keyword in Depth por egghead.io, que é extremamente recomendada!
Classes
Como mencionado anteriormente, não há um "mecanismo" de classes em JavaScript como os de linguagens de programação orientadas a objetos. No entanto, há funcionalidades para tornar possível a "simulação" de classes orientadas a objetos.
Vamos dar uma olhada na sintaxe para classes que foi introduzida ao JavaScript com o ES6, o que simplifica substancialmente a definição de classes (ou estruturas semelhantes a classes) em JavaScript.
No exemplo a seguir, definimos uma "classe" chamada Pessoa e dois objetos Pessoa:
class Pessoa {
constructor(nome, idade) {
this.nome = nome
this.idade = idade
}
cumprimentar() {
console.log('olá, meu nome é ' + this.nome)
}
}
const adam = new Pessoa('Adam Ondra', 29)
adam.cumprimentar()
const janja = new Pessoa('Janja Garnbret', 23)
janja.cumprimentar()
Quanto à sintaxe, as classes e os objetos criados a partir delas são muito semelhantes às classes e objetos Java. Seu comportamento também é bastante semelhante aos objetos Java. Mas em seu mecanismo interno, ainda são objetos baseados na herança prototipal de JavaScript. O tipo de ambos os objetos é, na verdade, Object, uma vez que o JavaScript essencialmente define apenas os tipos Boolean, Null, Undefined, Number, String, Symbol, BigInt e Object.
A inserção da sintaxe para classes foi uma adição controversa. Confira Not Awesome: ES6 Classes ou Is “Class” In ES6 The New “Bad” Part? on Medium para mais detalhes.
A sintaxe para classe ES6 é muito utilizada no "antigo" React e também no Node.js, portanto, é benéfico ter compreensão dela mesmo neste curso. Entretanto, como estaremos usando a nova funcionalidade Hooks do React ao longo deste curso, não teremos uso concreto da sintaxe para classes de JavaScript.
Materiais de JavaScript
Existem guias bons e ruins para JavaScript na Internet. A maioria dos links nesta página relacionados às funcionalidades de JavaScript referem-se ao Guia JavaScript da Mozilla.
É recomendado ler imediatamente o artigo A re-introduction to JavaScript (JS tutorial) no site da Mozilla.
Se deseja conhecer profundamente JavaScript, há uma ótima série de livros gratuitos na Internet chamada You-Dont-Know-JS.
Outra ótima fonte para aprender JavaScript é javascript.info.
O extremamente cativante e gratuito Eloquent JavaScript te leva rapidamente dos conceitos básicos à construção de aplicações muito interessantes. É uma mistura de teoria, projetos e exercícios, e cobre tanto a teoria geral de programação quanto a linguagem JavaScript.
egghead.io possui muitos screencasts de qualidade sobre JavaScript, React e outros tópicos interessantes. Infelizmente, alguns dos materiais só são acessíveis na versão paga.