Java para Web

Aula 03 : Javascript

Aula 03 - Javascript

Apresenta a estrutura básica do javascript e algumas estruturas avançadas

Exemplos de aula

Introdução ao Javascript

Especificações do Javascript
Javascript banner

O JavaScript é uma linguagem de programação dinâmica que foi criada por BrendanEich, também co-fundador do projeto Mozilla.

A flexibilidade do JavaScript permitiu que ele fosse utilizado em diversos ambientes,que vão muito além da interação dinâmica com páginas HTML, pro qual foi criado.

Atualmente, o JavaScript pode ser utilizado para construir aplicações para diversosdispositivos (deskop, mobile, web...) e diversos ecosistemas.

O JavaScript é padronizado pela ECMA International, uma organização parapadronização de sistemas de comunicação. Essa padronização é publicada através deespecificações, que por sua vez são utilizadas por empresas e projetos para projetarsuas próprias implementações do javascript.

Javascript em 2021

O Javascript ocupa atualmente a 7ª posição (relatório de agosto de 2021 da TIOBE Index) no ranking de linguagens mais populares, posição que tem se mantido estável desde o início do século XXI. No entanto, quando tratamos apenas linguagens para a Web, a linguagem javascript ganha um destaque único por ser, até o momento, a única linguagem largamente disponível nos navegadores. Essa condição faz do javascript uma linguagem essencial para quem trabalha com desenvolvimento de interfaces web (front-end), fato que pode ser comprovado através da primeira posição alcançada pela linguagem em serviços como StackOverflow e Github.

Em 2021, a linguagem (e vagas de emprego) deve continuar sendo impulsionada pela imensa quantidade de bibliotecas e frameworks desenvolvidos na linguagem, como os populares frameworks React.js, Vue.js e Angular.

Veja mais nesse Artigo

Vinculando Javascript no HTML

Para começar a escrever código JavaScript em uma página HTML, podemos de forma simples utilizar o elemento script para criar um novo script no mesmo documento ou apontar para um documento JavaScript externo.

Para referênciar um documento javacript pré-existente, podemos usar a sintaxe abaxo:

<script src="olamundo.js"></script>

Para escrever um script integrado no próprio documento HTML, usamos a seguinte sintaxe:

html index.html
<script>
    // Seu código aqui
</script>

Por boa prática, é comum encontrar estes elementos em dois locais específicos: dentro dohead ou logo abaixo do fim do body. Também podemos utilizar o atributo booleano async dentro do elemento script para indicar que o respectivo script será executado juntamente com o carregamento da página (dessa forma, ao encontrar um script, o navegador não para a leitura do HTML).

Geralmente utilizamos a segunda opção para importações ou operações simples em um documento HTML, enquanto realizamos a referência apresentada no primeiro exemplo para estruturas mais complexas. É importante lembrar que a ordem com que os elementos são utilizados pode ter efeitos no funcionamento dos scripts. Uma variável instanciada em um script no topo da página, por exemplo, estará automaticamente disponível para os scripts declarados logo abaixo.

Inspector Web
Ferramenta Inspector do Firefox

O inspector é uma das principais ferramentas aliadas do programador quando desenvolve interfaces para o navegador. É através dele que temos acesso a tudo que o navegador é capaz de interpretar sobre a página, seus erros e suas requisições. Além disso, o Inspector permite executar código javascript e alterar a estrutura e estilização da página em tempo de execução (enquanto a página está aberta), tornando-se uma ferramenta perfeita para o aprendizado.

Atalhos em cada navegador

Para abrir o inspector através de atalhos:

  • No Firefox, Chromium, Google Chrome e Opera, use F12

Fundamentos da Linguagem

Sintaxe do Javascript

A sintaxe do javascript é geralmente mais simples e mais flexível que grande parte das linguagens de programação populares. Abaixo um exemplo de um pequeno programa escrito em javascript:

js City.js
const cities = require('cities')
const cidadesLista = [587, 589, 600]
        
function validaCidade(cityId) {
    const city = cities.getById(cityId)
    if(city.length == 0){ 
        return false
    }
    return true
}

var sucesso = false
for(let cidadeId of cidadesLista){
    sucesso = validadeCidade(cidadeId)

    if(!sucesso){
        break
    }
}

console.log(sucesso)

Algumas características de sintaxe da linguagem:

  • Todos tipos números são representados pelo tipo number e são escritos com ponto como separador decimal (ex.: 10.50, 5, -20)
  • Variáveis podem ser declaradas com a palavra var (para variáveis acessíveis em todo o escopo) e let (acessíveis apenas dentro do mesmo escopo)
  • Um escopo no javascript é geralmente o espaço entre limitação das aspas
  • O uso de ponto e virgula (;) é totalmente opcional
  • O javascript é caseSensitive

Tipos de Dados do Javascript

Apesar de ser uma linguagem de tipagem dinâmica (os tipos de dados são automaticamente determinados), o JavaScript possui sete tipos de dados padrão:

  • Boolean
  • Null
  • Undefined
  • Number
  • String
  • Array
  • Object
  • Function*

Exemplos:

js index.js
var chovendo = false //bool
var inimigo = null //null
var casa =  //undefined
var pi = 3.14 //number
var nome = "ramon" //string
var lista = ["ramon", 0, null] //array
var data = {
    serie: 1,
    curso: "computacao"
} //object
var soma = function(a, b){
    return a + b
} //function

Veja mais em Mozilla - Javascript Data Structures

Apesar de não ser considerado oficialmente um tipo de variável, uma das características do javascript é a possibilidade de atribuir funções inteiras à variáveis e constantes.

Estruturas de Decisão do Javascript

IF/ELSE:

js index.js
if(condicao){
    // caso verdadeiro
} else {
    // caso falso
}

A estrutura clássica utilizada pela maioria das linguagens, que tem como objetivo rotear o fluxo de execução da aplicação.

Estruturas de Repetição do Javascript

FOR:

js index.js
for(var index = 0; index < 50; index++){
    // iteração
}

O for clássico utilizado pela maioria das linguagens para definir um contador e um incrementador, que tem como objetivo controlar o fluxo de repetição.

FOR-Of:

js index.js
for(var item of vetor){
    // iteração
}

Esse for é um caso especial muito útil para iterar sobre dados do tipo Enumerable (do qual os arrays, strings, objects e outros fazem parte). Dessa forma, podemos iterar sobre todas as posições de um vetor, por exemplo, sem saber seu tamanho. A cada iteração a variável chave receberá o valor de uma nova posição do vetor.

Veja mais em Mozilla - for ... of

FOR-In:

js index.js
for(var chave in objeto){
    // iteração
}

Assim como o for-in, o for-of também permite iterar sobre determinados tipos de dados. Todos os dados do tipo Iterable (do qual objects e arrays fazem parte) podem ser iterados por essa estrutura. A grande diferença é que quando utilizado com o tipo de dado objects (que não pode ser iterado com for-of), o valor recebido será a chave de cada propriedade, e não seu conteúdo.

Veja mais em Mozilla - for ... in

WHILE:

js index.js
while(condicao){
    // iteração
}

Outra estrutura clássica utilizada para repetição. Seu fluxo de execução depende apenas da condição definida como parâmetro.

Callbacks no Javascript

Funções callback no javascript são funções passadas como argumento para outra função, de forma que seja invocada a partir desta.

js index.js
var callbackChuva = function callbackChuva(){
    console.log('Está chovendo')
}

var callbackSol = function callbackSol(){
    console.log('Está fazendo sol')
}

function previsao(callback){
    callback()
}

previsao(callbackSol)

Este é um exemplo de callback executado de forma síncrona, ou seja, a sequência das funções é executada exatamente na ordem em que são chamadas. No entanto, a utilização de callbacks é largamente utilizada na criação de operações assíncronas, que acontecem de maneira paralela à execução do sistema.

setTimeout no Javascript

A função setTimeout permite adicionar, como parâmetro, uma função a ser executada após período de tempo também determinado em parâmetro. Essa função será chamada após o tempo determinado e apenas uma vez. A assinatura da função é: setTimeout(funcaoCallback, tempoEmMilisegundos)

js index.js
var resultado = function resultado(){
    console.log('Finalizado')
}

console.log(1)
setTimeout(resultado, 1000) // A função resultado será executada após 1000 milisegundos
console.log(2)
console.log(3)

Neste exemplo, a função resultado será chamada apenas após 1 segundo. Enquanto isso, a execução das próximas linhas não é interrompida.

setInterval no Javascript

A função setInterval permite adicionar, como parâmetro, uma função a ser executada em um período de tempo também determinado em parâmetro. A assinatura da função é: setInterval(funcaoCallback, tempoEmMilisegundos)

js index.js
var loop = function gameLoop(){
    console.log('Loop de um jogo completado com sucesso')
}

setInterval(loop, 5000) //A função gameLoop será executada em intervalos de 5 em 5 segundos

Neste exemplo, criamos uma função que imprime no console, a cada 5 segundos, a string: Loop de um jogo completado com sucesso

Promises no Javascript

Em 2015, a linguagem javascript incrementou sua sintaxe com o uso de Promises, que ajudam a organizar e extender o uso de callbacks.

Promises são objetos que representam processos assíncronos dentro do script. Uma promisse deve ser iniciada a partir de uma nova função, contendo os valores resolve e reject, que são chamados respectivamente no sucesso ou na falha da promessa.

js index.js
//Criando uma promessa
let promessa = new Promise(function (resolve, reject) {
    setTimeout(function () {
    if (Math.random() > 0.5) {
        console.log("Promessa resolvida")
        resolve()
    } else {
        console.log("Promessa rejeitada")
        reject()
    }
    }, 3000)
})
js index.js
//usando uma promessa
promessa.then(function () {
    document.getElementById("log").textContent = "finalizado"
}).catch(function () {
    document.getElementById("log").textContent = "erro"
}).finally(function () {
    console.log("Fim da promessa")
})
Recuperando Elemento com Javascript

Para recuperar um elemento já presente no DOM, vamos utilizar a função:

js Acessando um HTMLElement
var umaVariavel = document.querySelector("seletor")

Repare que no lugar de "seletor", vamos inserir um seletor no mesmo formato que já utilizamos no CSS (ex.: #id, .classe, input). Esse método sempre retorna o primeiro elemento encontrado na árvore DOM. Para encontrar todos os elementos, podemos utilizar:

js Acessando uma lista de HTMLElement
var umaLista = document.querySelectorAll("seletor")

Esse método retorna sempre um vetor, independente do número de ocorrências encontradas, contendo cada um dos elementos. Para acessá-los, podemos usar este for:

js Iterando um HTMLElement
for(var umElemento of umaLista){
    console.log(umElemento)
}

O chamado for of é um atalho de repetição que pode ser utilizado para qualquer tipo de variável iterável, que é o caso de um vetor. Ele percorre automaticamente todas as posições do vetor e finaliza quando este termina. Em cada iteração, a primeira variável assume o valor de um elemento. A alternativa clássica para a estrutura acima seria:

js Iterando um HTMLElement
for(var i = 0; i < umaLista.length(); i++){
    var umElemento = umaLista[i]
}
Elemento HTML

Quando acessamos um elemento HTML em qualquer página através do javascript, o dado retornado é geralmente apresentado na forma de Element ou HTMLElement. Ainda que não represente um tipo de dado, esse objeto é uma representação formalizada de um elemento contendo todos seus atributos e funções especificas que podem ser chamadas a partir desse método. Dessa forma, podemos acessar atributos como por exemplo class e id de qualquer elemento HTML.

js index.js
var elementoHTML = document.querySelector(".arena")
elementoHTML.id // Ex.: arena01
elementoHTML.classList // Ex.: DOMTokenList["arena"]

Outros atributos especificos de cada elemento também podem ser facilmente acessados diretamente a partir dele:

js index.js
var inputUsuario = document.querySelector("#inputUser")
inputUsuario.value // Ex.: "Jackie Chan"
inputUsuario.type // Ex.: "text"

Mais informações sobre o element

Criando um HTMLElement com Javascript

Em determinado momento, surge a necessidade de adicionar um novo elemento à uma página em tempo de execução. Por exemplo, ao clicar em um botão, você deseja adicionar um novo títuloh1 à página.

Apesar de ser possível inserir um novo elemento no DOM apenas alterando o conteúdo de texto, devemos criá-lo usando a interface DOM disponibilizada pelo navegador. Para isso, usaremos a seguinte sintaxe:

js Criando novo HTMLElement
var novoTitulo = document.createElement("h1")

Isso faz com que o DOM crie um novo elemento e armazene-o na variável novoTitulo. No entanto, ele não sera renderizado na tela. A razão é que ele foi criado apenas na memória e ainda não foi anexado à árvore do DOM. Faremos isso usando essa operação para acessar obody e adicionar o elemento:

js Adicionando novo elemento ao DOM
var novoTitulo = document.createElement("h1")
document.body.appendChild(novoTitulo)

Repare que passamos como parâmetro da função appendChild nosso novo títuloh1 recem criado. O novo título será anexado na árvore exatamente dentro do nó do qual a função appendChild foi chamada, ou seja, o nó body. No entanto, ainda não damos nenhum conteúdo de texto para nosso título, vamos fazer isso usando:

js Alterando texto do elemento criado ao DOM
var novoTitulo = document.createElement("h1")
document.body.appendChild(novoTitulo)
novoTitulo.textContent = "Meu novo título"

Substituímos o conteúdo da variável novoTitulo, mas como está é apenas um "apontador" para o elemento que foi anexado na árvore, ele será atualizado instantaneamente na página. É possível alterar qualquer atributo de um elemento HTML. Vamos alterar, por exemplo, o iddesse elemento:

js Alterando atributo ID de um elemento
novoTitulo.id = "titulo-novo"

Para alterar a classe de um elemento, também podemos usar as funções abaixo:

js Alterando classe de um HTMLElement
document.body.classList.add("umaClasse") // adiciona a classe umaClasse ao elemento
document.body.classList.remove("umaClasse") // adiciona a classe umaClasse ao elemento
Removendo Elemento do DOM com Javascript

Para remover um elemento pré-existente na árvore do DOM, podemos utilizar a funçãoremoveChild. Observe este exemplo:

html DOM
<ul>
    <li>Item 1</li>
    <li>Item 2</li>
    <li>Item 3</li>
</ul>
js Removendo um elemento do DOM
var pai = document.querySelector("ul")
var filho = pai.querySelector("li")
pai.removeChild(filho)

O código acima remove o primeiro elemento da lista ul. Repare que é necessário recuperar, além do elemento que queremos deletar, o seu pai, pois é ele quem renderiza os elementos filhos (assim como precisamos dele para adicionar um novo nó). No entanto, podemos usar a seguinte sintaxe para encontrar o elemento pai de um nó filho:

js Acessando elemento pai
var filho = document.querySelector("li")
var pai = filho.parentNode

Dessa forma, o atributo parentNode sempre retorna o elemento pai.

Eventos Javascript/HTML

No navegador, eventos de elementos podem ser escutados e repassados aos scripts.

Uma das formas de programar uma função para ser executada em um evento é identificando-a diretamente no HTML do evento

html index.html
<body>
    <button type="button" onClick="imprimir()">Enviar</button>
</body>
js index.js
function imprimir(){
    console.log("Botão apertado!")
}

No entanto, em alguns casos podemos optar (ou necessitar) por definir a escuta de um evento diretamente no javascript. Para isso, precisaremos resgatar o elemento HTML e definir uma função a ser executada, que pode ser feita da seguinte forma:

js index.js
function bgChange(evento) {
  evento.preventDefault()
  var rndCol = 'rgb(' + random(255) + ',' + random(255) + ',' + random(255) + ')';
  evento.target.style.backgroundColor = rndCol;
  console.log(evento);
}

btn.addEventListener('click', bgChange);

A função preventDefault(), que é chamada a partir do objeto evento serve para garantir que o navegador não irá executar nenhum processo padrão relacionado ao evento, o que acontece por exemplo ao submeter um formulário (uma requisição é automaticamente realizada pelo navegador)

Mais informações sobre o eventos

Manipulação de Vetores

Funções de Vetores

Por padrão, o javascript disponibiliza diversas funções para iteração e tratamento de vetores. O uso dessas funções está, geralmente, associado à uma melhor organização do código. Entre as diversas funções disponibilizadas por arrays, temos:

  • Array.map() utilizada para iterar sobre todos os elementos de um vetor
  • Array.sort() utilizada para ordenar os elementos de um vetor
  • Array.filter() utilizada para filtrar os elementos de um vetor
  • Array.reduce() utilizada reduzir o vetor a um único valor
  • Array.find() utilizada para buscar elementos em um vetor

map

O método map permite iterar um array chamando uma nova função para cada iteração. Esse métodosempre retorna um novo array como resultado.

js index.js
let minhaCallback = function conta(texto){
    return texto.length
}

var lista = ["verde", "amarelo", "azul"]
console.log(lista.map(minhaCallback))

Mais na documentação de map

sort

O método sort permite criar um comparador para vetores. Caso não seja passado um callback, o sort retorna uma conversão padrão para string e numbers. A função sort sempre altera o estado do vetor original.

js index.js
let minhaCallback = function compara(a, b){
    if(a.length > b.length){
        return -1
    }

    if(a.length < b.length){
        return 1
    }

    return 0
}

var lista = ["verde", "amarelo", "azul"]
console.log(lista.sort(minhaCallback))

No exemplo, o método `sort` itera sobre os elementos do vetor, organizando-os de acordo com o retorno especificado no callback.

Mais na documentação de sort

reduce

O método reduce permite executar uma função callback sobre um vetor de dados, resultado em um acumulador final. O método reduce sempre retorna um novo array.

js index.js
let minhaCallback = function soma(resultado, texto){
    return resultado + texto.length
}

let lista = ["verde", "amarelo", "azul"]
console.log(lista.reduce(minhaCallback, 0))

No exemplo, os itens da lista são iterados e acumulados em um acumulador.

Mais na documentação de reduce

filter

O método filter cria um array com todos os elementos que passaram no teste do callback. O método filter sempre retorna um novo array.

js index.js
let minhaCallback = function filtro(item){
    return item[0] === 'a'
}

var lista = ["verde", "amarelo", "azul"]
console.log(lista.filter(minhaCallback))

No exemplo, os itens da lista são filtrados de acordo com o critério retornado pelo callback.

Mais na documentação de filter

Orientação a Objetos

Classes

A declaração de classes pode ser realizada da seguinte maneira:

js index.js
class Casa {
    constructor() {
        this.numero = 42
    }

    endereco() {
        console.log('Número' + this.numero)
    }
}

var minhaCasa = new Casa() //Instancia o objeto
minhaCasa.endereco() // Olá Mundo

As classes no JavaScript, ao contrário de funções e variáveis, não são hoisted, o que significa que devem ser declaradas antes de sua utilização.

Mais na documentação de classes

Herança

O conceito de herança no javascript segue o conceito clássico de orientação a objetos:

js index.js
class Apartamento extends Casa {

}
Métodos Estáticos

Quando trabalhamos com classe, também podemos definir métodos estáticos:

js index.js
class App {
    static log() {
        console.log('Olá mundo')
    }
}

App.log() // Olá Mundo

Declarações

Variáveis

Há duas formas de declarar variáveis no javascript. A primeira é usando a palavra var, que é de escopo da função.

js index.js
var minhaVariavel; // declara variável
minhaVariavel = 10; // atribui valor à variável
minhaVariavel = "teste"; // atribui um novo à variável
var nome = "chapolin"; // declara e atribui valor à variável

A palavra reservada let declara variáveis acessíveis apenas no escopo mais próximo onde foram declaradas.

js index.js
function relatorio(){
    if(true){
        let nome = 'kratos'
        var poder = 40

        console.log(nome) // imprime normalmente
        console.log(poder) // imprime normalmente
    }

    console.log(nome) // erro de referencia
    console.log(poder) // imprime normalmente
}

relatorio()

console.log(nome) // erro de referencia
console.log(poder) // erro de referencia

A declaração usando a palavra let é geralmente recomendada pois evita desentendimento e reatrbuição de variáveis com escopo de função (var).

Constantes

As constantes no javascript possuem escopo de bloco e são semelhantes às variáveis declaradas usando let. A referência de uma constante não pode ser alterada por atribuição e ela não pode ser redeclarada.

No entanto é importante observar que no caso de objetos ou vetores, por exemplo, ainda é possível alterar o valor dos atributos e posições.

js index.js
const pi = 3.14
pi = 3 // ERRO

const jogo = {
    "nome": GTA 6
}
jogo.nome = "Fake" // OK
Arrow Functions

Arrow Functions são formas alternativas de declaração de funções:

js index.js
// Function expression
function(){

}

// Arrow Function expression
() => {

}

A principal diferença entre as Arrow Functions para as funções normais (usando a palavra reservada function) é que arrow functions não possuem seu próprio escopo this, como é verificado nas funções normais. Isso garante que essas funções irão assumir o contexto this do local onde foram chamadas, facilitando principalmente o uso com classes e objetos.

js index.js
class App {
    static executar(){
        console.log(function(){
            return this // Retorna undefined
        }())

        console.log((() => {
            return this // Retorna a classe App
        })())
    }
}

var app = new App()
App.executar()
Valor Padrão

Também é possível definir um valor padrão para os argumentos de uma função usando o operador de atribuição.

js index.js
function soma(a = 1, b = 2) {
    console.log(a + b)
}

soma(4) // 6

Operadores e Atribuições

Desestruturação

A desestruturação pode extrair dados de objetos e vetores diretamente de variáveis e constantes.

js index.js
const time = {
nome: 'Criciúma',
    dados: {
        sigla: 'CEC',
        site: 'criciumaesporteclube.com.br'
    }
}

let { nome } = time
console.log(nome) // Criciúma
let { dados: { site } } = time
console.log(site) // criciumaesporteclube.com.br
js index.js
function showName({ nome }) {
    console.log(nome)
}

const usuario = { nome: 'Ramon' }
showName(usuario) // Ramon
js index.js
const numeros = [1, 2, 3]
let [a, b, c] = numeros

console.log(a) // 1
console.log(b) // 2
console.log(c) // 3

Mais informações na documentação de desestruturação

Operador Rest

O chamado operador rest é utilizado como um açucar sintático para representar um número indeterminado de valores de um vetor em diferentes variáveis:

js index.js
const numeros = [1, 2, 3, 4, 5]

let [a, b, ...c] = numeros

console.log(a) // 1
console.log(b) // 2
console.log(c) // [3, 4, 5]
Operador Spread

O chamado operador spread pode ser utilizado como um açucar sintático para representar as propriedades de objeto ou os valores de um vetor:

js index.js
const usuario = {
    nome: 'ramon',
    empresa: 'unesc'
}

const novoUsuario = { ...usuario, nome: 'maradona' }

console.log(novoUsuario) // { nome: 'maradona', empresa: 'unesc' }
js index.js
function soma(x, y, z){
    return x + y + z
}

let numeros = [1, 2 , 3]
console.log(soma(...numeros))
Atalho Sintático para Objetos

Ao definir as propriedades de um objeto usando variáveis, podemos substituir a declaração caso o identificador da variável seja o mesmo da propriedade como no exemplo abaixo:

js index.js
const nome = 'Ronaldo'

const usuario = {
    nome // Mesma coisa que nome: nome
}

console.log(user.nome) // Ronaldo
Literals

O literals utiliza o apóstrofo para concatenar strings à variáveis ou constantes. Além do apóstrofo, é preciso utilizar a sintaxe $ para compor a variável.

js index.js
const a = 3
console.log(`O número é ${a}`. Boa sorte)

Mão na Massa

Exercício: Lista de Superherois

Usando esta lista de dados como referência, crie uma função que realize cada um dos seguintes processamentos no conjunto de dados, usando as funções array:

  • Usando map, crie uma lista com o alter_ego de todos os personagens
  • Usando reduce, retorne o tamanho total de caracteres de todos os first_appearance cujo o publisher é igual a "Marvel Comics"
  • Usando filter, imprima a lista apenas de personagens cujo o publisher é "DC Comics"
  • Usando sort, organize o vetor pelo tamanho do nome dos personagens (superhero)

Exercício: Futebol em Tempo Real

Você deverá criar uma página que simule partidas de futebol entre equipes acontecendo em tempo real, usando promises.

Para isso, crie um script que seja capaz de gerar novas promises e imprimir na tela uma lista com as promises iniciadas. Cada promise representa uma partida entre dois times de futebol digitados pelo usuário em um formulário com dois campos (para o nome de cada time).

Ao final do tempo de um tempo de 5 segundos, a promise deverá ser resolvida e o resultado da partida deverá ser mostrado na tela. Várias promises (partidas) podem rodar ao mesmo tempo.

O resultado da partida pode ser completamente aleatório

Exercícios Complementares

Exercício: Contador de Equipamentos

Crie um formulário que permita ao usuário digitar um texto longo (elementotextarea), e que retorne em uma div a quantidade de ocorrências para cada um dos seguintes itens:espada,arco e escudo

Exercício: Gerador de Calenário

Utilizando um javascript, crie três listas drop-down (elemento select) para apresentar ano, meses e dias.

Apenas anos entre 1990 e 1999 devem ser apresentados. Os meses devem estar entre Fevereiro e Agosto. E os dias do mês devem estar entre 05 e 25.

Todos os elementos devem ser gerados dinamicamente através do javascript (Dica: use estruturas de repetição)

Exercício: Pokedex

Crie uma pokédex contendo uma objeto com pelo menos 10 pokémons. O objeto deve conter número, nome, tipo e descrição e uma URL (local ou remota) com a imagem do pokémon. O usuário pode excluir, modificar ou inserir novos pokémons(com todas as suas informações). Ao final, deve-se apresentar um botão 'Showcase' que exibe imagem e nome dos pokémons a cada 3 segundos. Utilize CSS para estilizar o projeto à sua maneira =)

As informações podem ser retiradas diretamente desta API: https://pokeapi.co/

Exercício: Gerador de Mega-sena

Crie um função que gera de números de um sorteio de mega-sena. Como referência, o gerador deve apresentar um conjunto de 6 números de 1 a 60, sendo que cada número é único na sequência e não há possibilidade de repetir estes números em uma mesma jogada (amodal).

Em seguida, crie um formulário onde seja possível ao usuário "comprar tickets", definindo uma sequência amodal e registrando o ticket comprado na tela.

Por fim, a interface deve conter um botão de sorteio, que chama a função de sorteio e identifica se houve algum ticket ganhador

Ex.: O botão de sorteio pode ser implementado com algum tipo de timeout para exibir o ganhador