JavaScript
do zero ao real.
Material completo preparado por Felipe Duan (5º Período Ada) para a turma do 3º Período. Cobre toda a ementa com exemplos, analogias e exercícios.
O que é JavaScript?
JavaScript (JS) é uma linguagem de programação interpretada, dinâmica e multiparadigma. Foi criada em 1995 por Brendan Eich em apenas 10 dias e rapidamente se tornou a linguagem padrão dos navegadores.
Junto com HTML (estrutura) e CSS (estilo), o JavaScript forma o terceiro pilar do desenvolvimento web front-end — sendo responsável pelo comportamento e interatividade das páginas.
Apesar do nome, JavaScript não tem relação com a linguagem Java. O nome foi uma jogada de marketing para aproveitar a popularidade do Java na época.
A Tríade da Web
Pense assim — cada tecnologia tem uma responsabilidade clara:
HTML
Estrutura · O esqueleto da página. Define o que existe.
CSS
Aparência · A roupa. Define como as coisas parecem.
JavaScript
Comportamento · O cérebro e músculos. Define o que as coisas fazem.
O que dá para fazer com JS?
- Validar formulários antes do envio
- Animar elementos na página dinamicamente
- Buscar dados de APIs sem recarregar a página (Fetch — ver Parte 15)
- Criar aplicações inteiras no navegador (SPAs — Single Page Apps)
- Desenvolver back-end com Node.js
- Criar apps mobile com React Native
- Criar jogos, gráficos 2D/3D (Canvas, WebGL)
Como o navegador executa o JavaScript?
Cada navegador tem uma engine JavaScript que interpreta e executa o código:
| Navegador | Engine JS |
|---|---|
| Chrome / Edge | V8 |
| Firefox | SpiderMonkey |
| Safari | JavaScriptCore |
O fluxo de leitura de uma página é:
- O navegador lê o HTML e monta a árvore de elementos (DOM)
- Aplica o CSS e calcula os estilos
- Executa o JavaScript que pode modificar tudo isso
Como incluir JS no HTML
Existem três formas de adicionar JavaScript a uma página HTML:
1. Inline (no atributo do elemento)
<button onclick="alert('Olá!')">Clique aqui</button>
Mistura lógica com estrutura. Dificulta manutenção e reutilização. Evite sempre.
2. Interno (tag <script> no HTML)
<script> console.log("Olá, mundo!"); </script>
3. Externo (arquivo .js separado) ✅
<script src="script.js"></script>
Coloque a tag <script> no final do <body> ou use o atributo defer. Isso garante que o HTML já foi carregado quando o JS executar.
<!-- Com defer: carrega depois do HTML --> <script src="script.js" defer></script> <!-- Estrutura ideal de um arquivo HTML --> <!DOCTYPE html> <html> <head> <title>Minha Página</title> <link rel="stylesheet" href="style.css"> </head> <body> <!-- conteúdo aqui --> <script src="script.js"></script> <!-- aqui no final ✅ --> </body> </html>
Variáveis e Tipos de Dados
Variáveis são espaços na memória onde guardamos informações para usar depois. Em JavaScript moderno, usamos let e const.
Declarando variáveis
// let → valor pode mudar (variável) let nome = "Maria"; let idade = 22; nome = "João"; // ✅ OK, pode reatribuir // const → valor constante (não pode ser reatribuído) const PI = 3.14159; PI = 3; // ❌ Erro! Não pode reatribuir // var → evitar (escopo problemático, legado) var antigo = "não use";
Use const por padrão. Só mude para let se precisar reatribuir o valor. Nunca use var em código novo.
Tipos Primitivos
| Tipo | Exemplo | Descrição |
|---|---|---|
string | "Olá", 'mundo', `template` | Texto |
number | 42, 3.14 | Números inteiros e decimais |
boolean | true, false | Verdadeiro ou falso |
undefined | undefined | Variável declarada sem valor |
null | null | Ausência intencional de valor |
Verificando tipos com typeof
console.log(typeof "Olá"); // "string" console.log(typeof 42); // "number" console.log(typeof true); // "boolean" console.log(typeof undefined); // "undefined" console.log(typeof null); // "object" ← bug histórico do JS!
Template Literals (template strings)
Usam crase (`) e permitem interpolação com ${}:
const nome = "Ana"; const idade = 25; // Concatenação clássica (evitar) console.log("Meu nome é " + nome + " e tenho " + idade + " anos."); // Template literal ✅ console.log(`Meu nome é ${nome} e tenho ${idade} anos.`);
Operadores
Aritméticos
let a = 10, b = 3; console.log(a + b); // 13 (soma) console.log(a - b); // 7 (subtração) console.log(a * b); // 30 (multiplicação) console.log(a / b); // 3.33 (divisão) console.log(a % b); // 1 (módulo / resto) console.log(a ** b); // 1000 (exponenciação)
Comparação — ⚠️ Cai muito na prova!
Sempre prefira === e !== (comparação estrita). O == faz conversão automática de tipo e gera comportamentos inesperados.
console.log(5 == "5"); // true (compara só valor — CUIDADO!) console.log(5 === "5"); // false (compara valor E tipo) ✅ console.log(5 != "5"); // false console.log(5 !== "5"); // true ✅ console.log(10 > 5); // true console.log(10 <= 10); // true
Lógicos
console.log(true && false); // false (E — ambos precisam ser true) console.log(true || false); // true (OU — basta um ser true) console.log(!true); // false (NÃO — inverte)
Incremento e Atribuição
let x = 5; x++; // x = 6 (incrementa 1) x--; // x = 5 (decrementa 1) x += 10; // x = 15 (x = x + 10) x *= 2; // x = 30 (x = x * 2) x -= 5; // x = 25
Estruturas Condicionais
if / else if / else
const nota = 7.5; if (nota >= 7) { console.log("Aprovado! 🎉"); } else if (nota >= 5) { console.log("Recuperação 📋"); } else { console.log("Reprovado 😔"); }
Operador Ternário
Uma forma curta de escrever um if/else simples:
const idade = 18; // condição ? valorSeTrue : valorSeFalse const status = idade >= 18 ? "Maior de idade" : "Menor de idade"; console.log(status); // "Maior de idade"
switch
Use quando você precisa comparar uma variável com muitos valores possíveis:
const diaSemana = 3; switch (diaSemana) { case 1: console.log("Domingo"); break; case 2: console.log("Segunda"); break; case 3: console.log("Terça"); break; case 4: console.log("Quarta"); break; case 5: console.log("Quinta"); break; case 6: console.log("Sexta"); break; case 7: console.log("Sábado"); break; default: console.log("Dia inválido"); }
Não esqueça o break em cada case do switch! Sem ele, o código continua executando os cases seguintes (comportamento chamado "fall-through").
Estruturas de Repetição
Loops permitem executar um bloco de código várias vezes. O computador ama repetição — e é onde ele brilha.
for
// estrutura: for (inicialização; condição; incremento) for (let i = 1; i <= 5; i++) { console.log(`Número: ${i}`); } // Saída: Número: 1, Número: 2, ..., Número: 5
while
let contador = 1; while (contador <= 5) { console.log(`Contagem: ${contador}`); contador++; }
for...of (percorrer arrays)
const frutas = ["Maçã", "Banana", "Uva"]; for (const fruta of frutas) { console.log(fruta); } // Saída: Maçã, Banana, Uva
Use for...of para iterar valores de arrays. Para acessar índice e valor ao mesmo tempo, use o for clássico ou .forEach().
Funções
Funções encapsulam blocos de código reutilizáveis. São fundamentais para organizar e evitar repetição.
Declaração clássica
function saudacao(nome) { return `Olá, ${nome}!`; } console.log(saudacao("Carlos")); // "Olá, Carlos!"
O comando return
Existe diferença entre mostrar (console.log) e retornar (return) um valor. Uma função que usa return devolve um valor que pode ser guardado ou usado. console.log apenas exibe, não retorna nada útil.
function soma(a, b) { console.log(a + b); // só exibe } let result = soma(3, 4); console.log(result); // undefined!
function soma(a, b) { return a + b; // retorna } let result = soma(3, 4); console.log(result); // 7 ✅
Arrow Functions (ES6+)
// Sintaxe completa const somar = (a, b) => { return a + b; }; // Sintaxe curta (retorno implícito) const somar = (a, b) => a + b; console.log(somar(3, 7)); // 10
Parâmetros padrão
function potencia(base, expoente = 2) { // expoente padrão = 2 return base ** expoente; } console.log(potencia(5)); // 25 (expoente = 2) console.log(potencia(5, 3)); // 125 (expoente = 3)
Arrow functions são ideais para funções curtas e callbacks. Para métodos de objetos ou funções que precisam do this próprio, prefira a declaração clássica.
Arrays
Arrays são listas ordenadas de valores. Podem guardar qualquer tipo de dado e são indexados a partir do zero.
const frutas = ["Maçã", "Banana", "Uva"]; console.log(frutas[0]); // "Maçã" (índice 0) console.log(frutas[1]); // "Banana" (índice 1) console.log(frutas.length); // 3 (tamanho)
Métodos essenciais
const nums = [1, 2, 3]; nums.push(4); // [1, 2, 3, 4] → adiciona no fim nums.pop(); // [1, 2, 3] → remove do fim nums.unshift(0); // [0, 1, 2, 3] → adiciona no início nums.shift(); // [1, 2, 3] → remove do início // Verificar se inclui algo nums.includes(2); // true // Juntar elementos em string nums.join(" - "); // "1 - 2 - 3"
Métodos modernos (muito cobrados!)
const nums = [1, 2, 3, 4, 5]; // forEach — executa algo para cada item (não retorna) nums.forEach(n => console.log(n)); // map — cria um novo array transformando cada item const dobrados = nums.map(n => n * 2); console.log(dobrados); // [2, 4, 6, 8, 10] // filter — filtra itens que satisfazem uma condição const pares = nums.filter(n => n % 2 === 0); console.log(pares); // [2, 4] // find — encontra o primeiro item que satisfaz a condição const achou = nums.find(n => n > 3); console.log(achou); // 4 // reduce — reduz o array a um único valor const soma = nums.reduce((acc, n) => acc + n, 0); console.log(soma); // 15
Objetos
Objetos modelam entidades do mundo real usando pares de chave: valor. Pense em um objeto como uma ficha com propriedades.
const aluno = { nome: "Felipe", idade: 20, curso: "Engenharia de Software", ativo: true }; // Acessar propriedades console.log(aluno.nome); // "Felipe" (dot notation) console.log(aluno["idade"]); // 20 (bracket notation) // Alterar propriedade aluno.idade = 21; // Adicionar nova propriedade aluno.email = "felipe@email.com";
Objetos com métodos
const pessoa = { nome: "Ana", idade: 25, saudacao() { return `Olá, sou ${this.nome}!`; } }; console.log(pessoa.saudacao()); // "Olá, sou Ana!"
Desestruturação (muito usado)
const aluno = { nome: "João", curso: "Engenharia de Software", nota: 8.5 }; // Extrai propriedades direto em variáveis const { nome, nota } = aluno; console.log(nome); // "João" console.log(nota); // 8.5
DOM — Manipulação da Página
🏆 Este é o módulo mais importante para desenvolvimento web. É aqui que o JavaScript ganha superpoderes.
DOM (Document Object Model) é a representação da página HTML como uma árvore de objetos que o JavaScript pode ler e modificar em tempo real.
// O objeto 'document' representa a página inteira console.log(document); // a página HTML console.log(document.title); // título da aba console.log(document.body); // body da página
Selecionando elementos
// Por ID (único) — mais rápido const titulo = document.getElementById("meu-titulo"); // Por seletor CSS — mais flexível ✅ const botao = document.querySelector(".btn-enviar"); // primeiro match const itens = document.querySelectorAll("li"); // todos os matches // Seletores CSS funcionam igual: #id, .classe, tag, [atributo] const input = document.querySelector("input[type='email']");
Manipulando conteúdo
const el = document.querySelector("#mensagem"); // Ler e alterar texto puro (mais seguro) console.log(el.innerText); el.innerText = "Novo texto!"; // Ler e alterar HTML interno el.innerHTML = "<strong>Texto em negrito</strong>";
Manipulando estilos e classes
const caixa = document.querySelector(".caixa"); // Estilo direto (evitar para muitas mudanças) caixa.style.color = "red"; caixa.style.fontSize = "20px"; // Classes (preferível) ✅ caixa.classList.add("ativo"); // adiciona classe caixa.classList.remove("ativo"); // remove classe caixa.classList.toggle("escuro"); // adiciona/remove (toggle) caixa.classList.contains("ativo"); // true/false
Criando e inserindo elementos
// Criar um novo elemento const novoItem = document.createElement("li"); novoItem.innerText = "Nova tarefa"; novoItem.classList.add("item-lista"); // Inserir no DOM const lista = document.querySelector("#lista"); lista.appendChild(novoItem); // no final // Remover elemento novoItem.remove();
Lendo valores de inputs
const campo = document.querySelector("#nome"); // Ler valor digitado const valorDigitado = campo.value; // Limpar o campo campo.value = "";
Eventos
Eventos são ações do usuário ou do navegador que o JavaScript pode "escutar" e responder. É o que torna as páginas verdadeiramente interativas.
addEventListener — a forma correta
const botao = document.querySelector("#btn"); // elemento.addEventListener("evento", função) botao.addEventListener("click", function() { console.log("Botão clicado!"); }); // Com arrow function (mais moderno) botao.addEventListener("click", () => { console.log("Clicado!"); });
Eventos mais importantes
| Evento | Quando ocorre | Uso comum |
|---|---|---|
click | Clique do mouse | Botões, links |
input | Digitação em campo | Busca em tempo real |
submit | Envio de formulário | Validação |
keydown | Tecla pressionada | Atalhos, Enter |
mouseover | Mouse sobre elemento | Tooltips, hover |
mouseout | Mouse sai do elemento | Reset de hover |
change | Mudança em select/checkbox | Filtros |
DOMContentLoaded | HTML carregado | Inicialização |
O objeto event
botao.addEventListener("click", (event) => { console.log(event.target); // elemento que disparou console.log(event.type); // tipo do evento ("click") }); // Detectar qual tecla foi pressionada document.addEventListener("keydown", (e) => { console.log(e.key); // "Enter", "a", "Escape", etc. if (e.key === "Enter") { console.log("Enter pressionado!"); } });
Formulários
Formulários são a principal forma de capturar dados do usuário. JavaScript permite validar, interceptar e processar esses dados antes de qualquer envio.
preventDefault — essencial!
event.preventDefault() impede o comportamento padrão do formulário (recarregar a página ao enviar). Sem isso, a página recarrega e você perde os dados processados.
const formulario = document.querySelector("#meu-form"); formulario.addEventListener("submit", (event) => { event.preventDefault(); // ← SEMPRE coloque isso primeiro! const nome = document.querySelector("#nome").value; const email = document.querySelector("#email").value; // Validação if (nome === "") { alert("Por favor, preencha o nome!"); return; // para a execução } console.log(`Enviando para: ${email}`); });
Exemplo completo: formulário com validação
<!-- HTML --> <form id="form-cadastro"> <input type="text" id="nome" placeholder="Seu nome"> <input type="email" id="email" placeholder="Seu email"> <button type="submit">Enviar</button> <p id="mensagem"></p> </form> // JavaScript const form = document.querySelector("#form-cadastro"); const msg = document.querySelector("#mensagem"); form.addEventListener("submit", (e) => { e.preventDefault(); const nome = document.querySelector("#nome").value.trim(); const email = document.querySelector("#email").value.trim(); if (!nome || !email) { msg.innerText = "❌ Preencha todos os campos!"; return; } msg.innerText = `✅ Bem-vindo, ${nome}! Email: ${email}`; form.reset(); // limpa o formulário });
Recursos Modernos do JS
Spread Operator (...)
const a = [1, 2, 3]; const b = [4, 5]; const uniao = [...a, ...b]; // [1, 2, 3, 4, 5] // Clonar objetos const original = { nome: "Ana" }; const copia = { ...original, idade: 25 }; // { nome: "Ana", idade: 25 }
Métodos de String
const texto = " Olá, Mundo! "; texto.toUpperCase(); // " OLÁ, MUNDO! " texto.toLowerCase(); // " olá, mundo! " texto.trim(); // "Olá, Mundo!" (remove espaços das bordas) texto.includes("Mundo"); // true texto.split(","); // [" Olá", " Mundo! "] texto.replace("Olá", "Oi"); // " Oi, Mundo! " texto.startsWith(" Olá"); // true
Nullish Coalescing (??)
// Usa valor padrão quando a variável for null ou undefined const nome = null; const exibir = nome ?? "Anônimo"; console.log(exibir); // "Anônimo"
Optional Chaining (?.)
const usuario = { perfil: { avatar: "foto.jpg" } }; // Sem ?. — pode dar erro se perfil for undefined console.log(usuario.endereco.rua); // ❌ TypeError // Com ?. — retorna undefined sem quebrar console.log(usuario?.endereco?.rua); // undefined (sem erro) ✅
JavaScript moderno: ES6+, Promises, async/await e módulos
A partir do ES6 (ES2015) o JavaScript ganhou sintaxe e recursos que hoje são o padrão em tutoriais, ferramentas e APIs do navegador. Esta parte organiza o que mais aparece no dia a dia — inclusive por baixo do fetch, que você verá na Parte 15.
Você já viu arrow functions, template literals e trechos de ES6+ nas partes anteriores (e recursos como spread e optional chaining na Parte 13). Aqui o foco é: desestruturação, rest/parâmetros padrão, o modelo mental de Promise, .then() vs async/await e import/export.
Desestruturação — extrair valores de objetos e arrays
Em vez de acessar campo por campo, você “abre” a estrutura na declaração.
// Objeto — nomes devem bater com as chaves const turma = { id: 1, nome: "ADA", periodo: 5 }; const { nome, periodo } = turma; console.log(nome, periodo); // "ADA" 5 // Renomear na hora const { nome: titulo } = turma; // Array — posição importa const coords = [10, 20]; const [x, y] = coords;
Parâmetros padrão e rest (...)
// Valor padrão se o argumento vier undefined function saudar(nome = "visitante") { return `Olá, ${nome}!`; } // Rest — agrupa o "resto" dos argumentos em um array function soma(...numeros) { return numeros.reduce((acc, n) => acc + n, 0); } soma(1, 2, 3); // 6
O spread de arrays/objetos (clonar, juntar) você revisa na Parte 13 — é o mesmo ..., em outro contexto.
Promise — “um valor que ainda vai chegar”
Operações assíncronas (rede, timers, leitura de arquivo no Node…) não bloqueiam a fila principal. O navegador modela muitas delas com Promises: um objeto que representa eventualmente sucesso (fulfilled) ou falha (rejected).
const promessa = new Promise((resolve, reject) => { // função executora — chamada resolve(valor) ou reject(erro) setTimeout(() => resolve(42), 500); }); promessa .then(valor => console.log(valor)) // 42 .catch(err => console.error(err)) .finally(() => console.log("fim"));
.then(callback)— roda quando a Promise resolve; retorna uma nova Promise (permite encadear)..catch(callback)— trata rejeição (ou exceção dentro de umthen)..finally(callback)— roda no fim, com sucesso ou erro (limpeza de UI, etc.).
Encadeamento com .then()
Cada .then pode devolver um valor ou outra Promise; o próximo elo espera esse resultado. Assim você evita “callback hell” em estilo antigo — mas muitos .then seguidos ainda podem ficar difíceis de ler.
fetch("https://api.exemplo.com/dados") .then(res => { if (!res.ok) throw new Error("HTTP " + res.status); return res.json(); // devolve Promise → próximo .then recebe o objeto }) .then(dados => console.log(dados)) .catch(err => console.error(err));
async / await — mesma Promise, outra leitura
async function sempre retorna uma Promise. Dentro dela, await pausa só essa função até a Promise resolver — o código parece síncrono, linha a linha.
async function carregar() { const res = await fetch("https://api.exemplo.com/dados"); if (!res.ok) throw new Error("HTTP " + res.status); const dados = await res.json(); console.log(dados); }
Mesma máquina: await é só açúcar sobre Promises. Equipes modernas costumam preferir async/await para fluxos longos e try/catch. .then() continua válido em encadeamentos curtos ou quando você não quer marcar a função inteira como async. Em provas, entender os dois conta mais que escolher um estilo.
| Aspecto | .then() | async / await |
|---|---|---|
| Erros | .catch() no encadeamento | try { ... } catch { ... } |
| Último valor | Cada return passa ao próximo then | return normal dentro da função async |
| Funções paralelas | Promise.all([...]) | await Promise.all([...]) |
// Duas requisições em paralelo — espera as duas terminarem async function carregarDois() { const [a, b] = await Promise.all([ fetch("/api/a").then(r => r.json()), fetch("/api/b").then(r => r.json()), ]); console.log(a, b); }
Módulos ES — import e export
Em projetos reais (e em trabalhos que pedem script.js separado), você divide código em arquivos. O padrão oficial no navegador é ES Module: cada arquivo é um módulo com escopo próprio.
// export nomeado — vários por arquivo export function formatarData(iso) { /* ... */ } export const API_BASE = "https://api.exemplo.com"; // export default — no máximo um por arquivo (o “principal”) export default function criarCard(item) { /* ... */ }
import criarCard from "./helpers.js"; // default import { formatarData, API_BASE } from "./helpers.js"; // nomeados import { formatarData as fmt } from "./helpers.js"; // alias
<!-- O navegador baixa módulos com defer implícito — ordem importa pelos imports --> <script type="module" src="./app.js"></script>
import usa caminhos relativos (./) na maioria dos projetos. Abrir HTML pelo protocolo file:// pode bloquear módulos por política do navegador — use um servidor local simples (ex.: extensão Live Server, ou python -m http.server) ao testar type="module".
import() dinâmico (carregar sob demanda)
A forma estática acima é analisada em tempo de build/carregamento. Às vezes você só quer carregar um módulo depois de um evento — aí existe import('./modulo.js'), que devolve uma Promise.
botao.addEventListener("click", async () => { const { graficosExtras } = await import("./graficos.js"); graficosExtras(); });
Fetch devolve uma Promise de Response; por isso combina naturalmente com .then ou await. Na Parte 15 você aplica isso a APIs REST e JSON.
HTTP no navegador, Fetch API e JSON
O método fetch retorna uma Promise de Response — combinar com .then() ou await é o mesmo modelo da Parte 14. Quando uma página precisa buscar ou enviar dados para um servidor (por exemplo uma API REST), o navegador faz uma requisição HTTP. Em código moderno isso costuma ser feito com fetch e dados em formato JSON.
Você já usa DOM, eventos e formulários. O fluxo típico: usuário envia um formulário → você monta um objeto JavaScript → JSON.stringify no corpo do POST → await fetch(...) (ou .then) → atualiza a tela com innerHTML/createElement usando a resposta, sem recarregar a página.
Request e response — visão rápida
- URL — endereço do recurso (ex.:
/turmas). - Método —
GET(ler),POST(criar/enviar dados), entre outros. - Status HTTP — número que diz se deu certo ou não (
200OK,400/422erro de validação,404não encontrado,500erro no servidor). - Corpo — em APIs JSON, quase sempre texto JSON enviado ou recebido.
| Status | Significado comum | O que fazer na UI |
|---|---|---|
200 / 201 | Sucesso | Mostrar confirmação; atualizar lista/dados na tela |
400 / 422 | Dados inválidos | Ler mensagem da API (se houver) e exibir ao usuário |
404 | Recurso não existe | Avisar que não foi encontrado |
500+ | Falha no servidor | Mensagem genérica “tente novamente”; não culpar o usuário |
JSON — formato texto dos dados
Na linguagem JS você trabalha com objetos e arrays. Na rede os dados viram string JSON. Duas funções fazem a ponte:
const objeto = { nome: "ADA", periodo: 5 }; // Objeto → string JSON (para enviar no body) const texto = JSON.stringify(objeto); // '{"nome":"ADA","periodo":5}' // String JSON → objeto (para ler response) const deVolta = JSON.parse(texto);
GET com fetch — buscar dados
Por padrão fetch(url) já usa método GET. A resposta não é o JSON pronto: primeiro você obtém o objeto Response, depois chama .json() (assíncrono).
async function carregarTurmas() { const url = "https://api.exemplo.com/turmas"; const resposta = await fetch(url); if (!resposta.ok) { console.error("Erro HTTP", resposta.status); return; } const lista = await resposta.json(); console.log(lista); // array ou objeto — depende da API }
POST com JSON — criar recurso
Envie o cabeçalho Content-Type: application/json e o corpo como string JSON.
async function criarTurma(nome, periodo, ano) { const resposta = await fetch("https://api.exemplo.com/turmas", { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ nome, periodo, ano }), }); if (!resposta.ok) { // opcional: const erro = await resposta.json(); throw new Error("Falha ao criar"); } return await resposta.json(); }
Validação antes do fetch
O servidor também valida — mas você deve validar no JS antes de chamar a API: campos vazios, formato de email, número em intervalo válido, etc. Use os mesmos padrões da Parte 12 (preventDefault, trim, mensagens em um elemento na página).
try/catch — rede e exceções
fetch só “quebra” com catch em erros de rede (offline, DNS, CORS bloqueado conforme o caso). Um HTTP 404 ou 422 não lança exceção por si só — por isso sempre combine com response.ok ou response.status.
try { const res = await fetch(url); if (!res.ok) { mostrarErro(`Servidor respondeu ${res.status}`); return; } const dados = await res.json(); mostrarSucesso(dados); } catch (e) { mostrarErro("Sem conexão ou URL inválida."); }
Browsers aplicam a política CORS: o servidor precisa autorizar o seu domínio nas respostas. No Postman ou curl isso não aparece — lá funciona e no site pode falhar. Se a API da disciplina já permite seu front, ótimo; se não, só o professor/servidor pode ajustar.
1) GET ao carregar para listar. 2) POST em submit com preventDefault. 3) Atualizar o DOM após sucesso (sem location.reload()). 4) Mensagens claras para sucesso e para cada faixa de erro HTTP. 5) Separar HTML / CSS / JS em arquivos se o enunciado pedir.
Erros Comuns e Debug
Erros mais frequentes
| Erro | Causa | Solução |
|---|---|---|
ReferenceError |
Variável não existe | Verificar nome e escopo |
TypeError |
Tipo errado (null, undefined) | Verificar se elemento existe no DOM |
SyntaxError |
Erro de sintaxe no código | Procurar colchete/chave faltando |
Cannot read property of null |
Elemento não encontrado no DOM | Verificar seletor CSS ou posição do script |
Ferramentas de debug
// console.log — sua principal ferramenta console.log("Verificando valor:", variavel); // console.error — destaca erros em vermelho console.error("Algo deu errado!"); // console.table — exibe arrays/objetos como tabela console.table(meuArray); // typeof — para entender o tipo de uma variável console.log(typeof minhaVariavel); // Verificar se elemento existe antes de usar const el = document.querySelector("#meu-id"); if (el) { el.innerText = "Seguro!"; // só executa se encontrar }
Pressione F12 no navegador para abrir o DevTools. A aba Console mostra erros e logs. A aba Elements mostra o DOM em tempo real. A aba Sources permite debugar linha a linha.
Aba Network — requisições HTTP
A aba Network lista cada requisição feita pela página: método (GET/POST), URL, status HTTP, tempo e tamanho da resposta. Ao trabalhar com fetch, selecione a linha correspondente e confira Headers e Response — você vê o JSON bruto que a API devolveu (ou o corpo de erro). Sem isso, adivinhar por que a lista não atualiza vira perda de tempo.
Exercícios Práticos
Nível 1 — Fundamentos
- Declare variáveis com seu nome, idade e curso usando
constelet. Exiba uma apresentação com template literal. - Crie uma função que recebe uma nota e retorna "Aprovado", "Recuperação" ou "Reprovado".
- Faça um loop que exibe a tabuada do 7 completa no console.
- Crie um array com 5 frutas e exiba cada uma usando
for...of. - Crie um objeto representando um produto com nome, preço e estoque.
Nível 2 — DOM e Eventos
- Crie um botão que, ao ser clicado, muda o texto de um parágrafo.
- Faça um contador com botões de + e − que exibe o valor na tela.
- Implemente um botão de dark/light mode que troca a classe do
body. - Crie um campo de busca que filtra itens de uma lista conforme o usuário digita.
- Faça um botão "mostrar/esconder senha" em um campo de senha.
Nível 3 — Projetos
- To-do List: Adicione tarefas, marque como concluídas e remova.
- Calculadora: Interface com botões numéricos e operações básicas.
- Formulário com validação: Nome, email e senha com feedback visual.
- Quiz: 5 perguntas de múltipla escolha com pontuação final.
Nível 4 — JS moderno e API (integração)
- Crie
helpers.jscom um export nomeado (ex.: função que formata texto) e um export default; emapp.js, importe os dois comimporte use no DOM. Suba com servidor local e<script type="module">. - Escreva a mesma função que carrega dados usando só
.then()/.catch(); depois reescreva comasync/await+try/catch. Compare a legibilidade. - Consuma uma API pública (ex.: JSONPlaceholder) com
fetch: primeiro encadeando.then, depois em uma versãoasync. Liste itens no DOM e trate!response.ok. - Monte um POST com corpo JSON; valide campos no JS antes de enviar e exiba mensagens diferentes para sucesso e para erro HTTP (400/422/404).
- No DevTools → Network, compare uma chamada feita com encadeamento
.thene outra comawait— método, status e corpo devem ser iguais; só muda o estilo do código.
Caia sempre em: == vs ===, DOM, eventos com addEventListener, return, let / const / var. Em código atual: Promises, async/await ou .then(), e organização com módulos. Para trabalhos com servidor: fetch, JSON, validação de formulário e status HTTP na interface (layout responsivo é CSS da disciplina — use Flexbox/Grid nas folhas de estilo).