JavaScript Essencial
Um checklist dos fundamentos de JavaScript moderno: cada tópico em poucas linhas, com o snippet mínimo e as armadilhas. Se ao ler algo você sentir que não domina, o ponteiro → aprofunde em… indica a apostila completa. Serve de revisão pré-entrevista, de mapa para quem está começando, e de referência rápida no dia a dia.
O formato "Essencial"
Uma apostila-checklist: densa, sem rodeios, feita para ser varrida — não lida linha a linha.
- Leia rápido. Se você reconhece o tópico e sabe o snippet de cor, siga. Se travou, é sinal de estudar.
- Os → aprofunde em… apontam para as apostilas completas: JavaScript Fullstack, Full Stack com TypeScript & Next.js, Next.js, DevTools & Debug, Aceleração de Código com IA.
- As caixas ⚠️ armadilha são o que mais cai em entrevista e o que mais gera bug — não pule.
- A auto-checagem no fim de cada seção: se você não responde de cabeça, volte.
- O checklist final é a lista literal para marcar antes de dizer "sei o básico de JS".
Tipos, valores e coerção
7 primitivos + objeto. Tudo que não é primitivo é objeto (incluindo array e função). → aprofunde em JavaScript Fullstack
| Primitivo | Notas |
|---|---|
string | Imutável. Aspas ou template literal `...${x}...` |
number | Um só tipo (float 64). 0.1+0.2 !== 0.3. NaN, Infinity |
bigint | 10n — inteiros grandes exatos |
boolean | true/false |
undefined | "não foi atribuído" (default de variável/param/retorno) |
null | "ausência intencional" (você põe). typeof null === "object" (bug histórico) |
symbol | Identificador único; chaves não-colidentes |
Checagem e igualdade
typeof x // "string" | "number" | ... | "object" | "function" | "undefined" Array.isArray(x) // typeof [] é "object" — use isso p/ array x === y // SEMPRE. Sem coerção. x == y // coage — evite. Exceção comum: x == null pega null E undefined Number.isNaN(x) // NaN !== NaN — a única forma correta de testar NaN Object.is(x, y) // como === mas Object.is(NaN,NaN)===true e -0 !== +0
Truthy / falsy
Falsy (só estes 8): false, 0, -0, 0n, "", null, undefined, NaN. Todo o resto é truthy — incluindo "0", "false", [], {}.
if (x)quandoxpode ser0ou""válido → useif (x != null)oux !== undefined.- Somar string com número coage:
1 + "2" === "12", mas1 - "2" === -1. [] == ![]étrue— é por isso que não se usa==.- Primitivos são copiados por valor; objetos/arrays/funções são copiados por referência.
✔️ Auto-checagem
Quais os 8 valores falsy? Por que [] == false? Como testar NaN? Diferença entre null e undefined na prática? typeof de [], de null, de uma função?
Variáveis, escopo e closures
const por padrão, let quando reatribui, var nunca. → aprofunde em JavaScript Fullstack
| Escopo | Hoisting | Reatribui? | |
|---|---|---|---|
const | bloco { } | TDZ (erro se usar antes) | não (o binding; o objeto ainda muta por dentro) |
let | bloco { } | TDZ | sim |
var | função (ignora blocos) | sobe como undefined | sim — legado, evite |
Closure
Uma função "lembra" as variáveis do escopo onde foi criada, mesmo depois que esse escopo terminou.
function contador() { let n = 0; return () => ++n; // esta arrow fecha sobre `n` } const next = contador(); next(); next(); // 1, 2 — `n` sobrevive, privado
Usos: estado privado, memoização, factories, handlers que capturam contexto.
- Loop com
var+ callback assíncrono → todos veem o último valor. Comlet, cada iteração tem seu binding. - Closure capturando um objeto grande num handler que nunca é removido = memory leak (→ DevTools & Debug, Módulo 6).
const obj = {...}não impedeobj.x = 1. Para congelar:Object.freeze(obj)(raso).
✔️ Auto-checagem
O que é TDZ? Por que let no for resolve o clássico "todos imprimem 3"? Escreva uma factory que retorna funções com estado privado. const torna o valor imutável?
Funções e this
Funções são valores (first-class). Arrow ≠ function quanto a this. → aprofunde em JavaScript Fullstack
function f(a, b = 1, ...rest) { } // default + rest params const g = (a, b) => a + b; // arrow: retorno implícito, sem { } const h = a => ({ a }); // retornar objeto: parênteses (function(){ ... })(); // IIFE
As 4 regras de this (para function, resolvido na CHAMADA)
| Chamada | this é |
|---|---|
obj.metodo() | obj (o objeto à esquerda do ponto) |
fn() avulsa | undefined (strict) / window (sloppy) |
new Fn() | o objeto novo criado |
fn.call(x) / .apply(x) / .bind(x) | x (explícito) |
Arrow function: não tem this próprio — usa o do escopo onde foi definida (lexical). Também não tem arguments, não serve de construtor, não tem prototype.
- Passar
obj.metodocomo callback "perde" othis→obj.metodo.bind(obj)ou() => obj.metodo(). - Método de objeto como arrow →
thisnão é o objeto (é o de fora). Usefunction/method shorthand para métodos. - Handler de evento com arrow:
thisnão é o elemento; usee.currentTarget. argumentsnão é array de verdade →[...arguments]ou use rest...args.
✔️ Auto-checagem
As 4 regras de this. Por que arrow "conserta" o this em callbacks? Quando NÃO usar arrow? Diferença entre call, apply e bind?
Objetos e arrays
Destructuring, spread, optional chaining e nullish são o vocabulário do dia a dia. → aprofunde em JavaScript Fullstack
// literal + shorthand + computed key const nome = "Ana", chave = "id"; const u = { nome, [chave]: 1, saudar() { return `Oi, ${this.nome}` } }; // destructuring (com default e rename) const { nome: n, idade = 0, ...resto } = u; const [primeiro, , terceiro] = arr; function f({ a, b = 10 }) { } // destructuring em parâmetro // spread (cópia RASA) e merge const copia = { ...u, idade: 30 }; // último vence const arr2 = [...a, ...b, 99]; // acesso seguro u?.endereco?.rua // undefined se algo no caminho for null/undefined u.telefone ?? "sem tel" // fallback SÓ se null/undefined (não se 0 ou "") u.lista?.[0] // optional chaining com índice minhaFn?.() // chama só se existir
Utilitários de objeto
Object.keys(o) / .values(o) / .entries(o) // arrays Object.assign(alvo, ...fontes) // merge raso (muta alvo) Object.freeze(o) // imutável raso structuredClone(o) // cópia PROFUNDA (moderno) JSON.parse(JSON.stringify(o)) // cópia profunda antiga (perde Date, undefined, fn...) "x" in o / o.hasOwnProperty("x") / Object.hasOwn(o, "x")
- Spread e
Object.assignsão rasos: objetos aninhados continuam compartilhados. Para profundo:structuredClone. { ...a, ...b }: chaves debsobrescrevema.??vs||:0 || 5é5(bug);0 ?? 5é0(correto para "valor default só se ausente").- Comparar objetos com
===compara referência, não conteúdo. - Ordem de chaves: inteiras primeiro (ascendente), depois strings na ordem de inserção.
✔️ Auto-checagem
Diferença entre ?? e ||. Como copiar profundamente um objeto? Destructure {a, b: {c}} com default para c. O que ?. retorna quando o caminho quebra?
Métodos de array
Prefira os que não mutam e retornam novo array. → aprofunde em JavaScript Fullstack · Algoritmos com Python (conceitos de complexidade)
| Método | Retorna | Nota |
|---|---|---|
map(fn) | novo array, mesmo tamanho | transformar |
filter(fn) | novo array, ≤ tamanho | fn retorna boolean |
reduce(fn, init) | um valor acumulado | sempre passe init |
find(fn) / findIndex(fn) | 1º elemento / índice, ou undefined/-1 | para no 1º match |
some(fn) / every(fn) | boolean | "existe algum" / "todos" |
includes(v) / indexOf(v) | boolean / índice | includes acha NaN |
flatMap(fn) / flat(d) | novo array achatado 1 nível | |
forEach(fn) | undefined | só efeito colateral; não dá para break |
slice(i, j) | novo array (fatia) | não muta |
sort(fn) · reverse() · splice() · push/pop/shift/unshift · fill | — | MUTAM o original |
toSorted · toReversed · toSpliced · with | novo array | versões imutáveis (ES2023) |
// encadeamento típico const total = pedidos .filter(p => p.pago) .map(p => p.valor) .reduce((s, v) => s + v, 0); // iterar: for...of dá break/continue e await; forEach não for (const item of lista) { if (cond) break; }
sort()sem comparador ordena como string:[10, 2, 1].sort()→[1, 10, 2]. Usesort((a,b) => a - b). Esortmuta.reducesem valor inicial num array vazio → erro.forEachignorareturn, não esperaawait, não dábreak. Para async sequencial:for...of+await.mapsó para transformar; se você não usa o retorno, erafor...of/forEach.- Métodos que mutam num state de React/Vue = bug de reatividade. Use spread ou
toSorted/with.
✔️ Auto-checagem
Quais métodos mutam? Por que [3,20,1].sort() dá [1,20,3]? Quando for...of em vez de forEach? Escreva um reduce que agrupa por chave.
Assíncrono: event loop, Promises, async/await
JS é single-thread: o assíncrono não é paralelismo, é agendamento. → aprofunde em JavaScript Fullstack · Next.js (RSC/streaming)
Event loop em uma frase
A stack roda até esvaziar; então processa todas as microtasks (Promises, queueMicrotask); depois uma macrotask (timer, evento, I/O); repete. Por isso Promise.then roda antes de setTimeout(…, 0).
const p = new Promise((resolve, reject) => { ... }); // pending → fulfilled | rejected p.then(v => ...).catch(e => ...).finally(() => ...); async function f() { try { const a = await fetch(url); // pausa a função, não a thread const data = await a.json(); return data; // async sempre retorna Promise } catch (e) { ... } // pega rejeições dos await }
Combinadores
| Resolve quando | Rejeita quando | |
|---|---|---|
Promise.all([...]) | todas resolvem → array de valores | a 1ª que rejeitar (as outras continuam rodando) |
Promise.allSettled([...]) | todas terminam → {status, value/reason}[] | nunca |
Promise.race([...]) | a 1ª a resolver | a 1ª a rejeitar |
Promise.any([...]) | a 1ª a resolver | só se todas rejeitarem (AggregateError) |
// paralelo (as 3 disparam juntas): const [a, b, c] = await Promise.all([getA(), getB(), getC()]); // sequencial (uma espera a outra) — só se houver dependência: for (const id of ids) { await processar(id); }
- Esquecer
await→ você tem umaPromisependente, não o valor; e a rejeição vira unhandled. array.forEach(async …)não espera nada. Usefor...of+await, ouPromise.all(array.map(async …)).awaitdentro demapsemPromise.allnão serializa — cada callback é independente.Promise.allfalha tudo no 1º erro; se você quer os resultados parciais,allSettled.- Erro dentro de um
.thensem.catchdepois → unhandled rejection. - Loop pesado síncrono trava a UI inteira — não há await que ajude; quebre o trabalho.
✔️ Auto-checagem
Por que then roda antes de setTimeout(0)? Qual a diferença entre all e allSettled? Como disparar 3 fetches em paralelo e esperar todos? Por que forEach(async) não funciona como esperado?
Classes e protótipos
class é açúcar sobre a cadeia de protótipos. → aprofunde em JavaScript Fullstack
class Animal { #energia = 100; // campo privado (só dentro da classe) static reino = "Animalia"; // na classe, não na instância constructor(nome) { this.nome = nome; } mover() { this.#energia--; } get vivo() { return this.#energia > 0; } // getter: acessa como propriedade } class Gato extends Animal { constructor(nome) { super(nome); } // super() antes de usar this mover() { super.mover(); console.log("miau"); } } const g = new Gato("Tom"); g instanceof Animal; // true
Por baixo
- Todo objeto tem um protótipo (
Object.getPrototypeOf(o)); acessaro.xsobe a cadeia até achar ou chegar anull. - Métodos de classe ficam no
Prototype(compartilhados); campos de instância são copiados por objeto. classnão é hoisted (TDZ); o corpo roda em strict mode.
- Usar
thisantes desuper()na subclasse → erro. - Passar
g.movercomo callback perde othis(seção 03). Solução: campo de classe com arrow (mover = () => {...}) oubindno constructor. #privadoé privado de verdade (não é convenção como_x).- Herança profunda quase sempre é sinal de design ruim — prefira composição.
✔️ Auto-checagem
O que class "esconde"? Por que super() antes de this? Diferença entre método (no prototype) e campo de instância. O que instanceof checa?
Módulos
ESM (import/export) é o padrão. → aprofunde em JavaScript Fullstack · Next.js
// export export const PI = 3.14; // named export function soma(a, b) {} // named export default class Cliente {} // default (um por arquivo) export { a, b as bee }; // lista / rename // import import Cliente, { PI, soma } from "./mod.js"; import * as mod from "./mod.js"; const m = await import("./pesado.js"); // dinâmico → code splitting
| ESM | CommonJS (Node legado) | |
|---|---|---|
| Sintaxe | import / export | require() / module.exports |
| Carregamento | estático, assíncrono, top-level await | síncrono |
| Tree-shaking | sim (imports estáticos) | não |
| Ativar | "type": "module" ou .mjs; padrão em bundlers/browser | padrão antigo do Node |
- Não misture
requireeimportno mesmo arquivo sem entender ointerop. - Bindings de ESM são vivos e read-only: você não reatribui um
import. - Ciclos de import podem dar
undefinedtemporário — evite dependência circular. import()dinâmico é como você faz lazy load de rotas/componentes.
✔️ Auto-checagem
Named vs default export — quando cada um? Por que ESM permite tree-shaking e CJS não? Como fazer lazy load de um módulo? O que import * as traz?
Erros e robustez
Trate a falha onde você pode decidir algo; senão, propague. → aprofunde em JavaScript Fullstack · DevTools & Debug
try { arriscado(); } catch (e) { if (e instanceof TypeError) { ... } throw new Error(`ao processar: ${e.message}`, { cause: e }); // re-lança com contexto } finally { limpar(); // sempre roda } class ValidationError extends Error { constructor(campo) { super(`inválido: ${campo}`); this.name = "ValidationError"; this.campo = campo; } }
throwpode lançar qualquer valor, mas sempre lance umError(temstack,name,message).Error.cause(ES2022) encadeia o erro original.- Assíncrono:
awaitdentro detry/catchcaptura rejeições;.catch()na Promise faz o mesmo. - Globais:
window.addEventListener("unhandledrejection", …)e"error"(browser);process.on("unhandledRejection", …)(Node).
catchvazio oucatch (e) { console.log(e) }e seguir como se nada = engolir o erro.- Promise rejeitada sem
.catch/try` → unhandled rejection (crash no Node moderno). try/catchnão pega erro dentro de umsetTimeout/callback assíncrono não-await.- Não use exceções para fluxo normal (ex.: "não encontrado" pode ser um valor de retorno).
✔️ Auto-checagem
Quando finally roda? Como criar um erro custom? Como capturar a rejeição de um await? O que é Error.cause? Por que nunca throw "string"?
O resto do essencial
Itens que caem e você tem que reconhecer. → aprofunde em JavaScript Fullstack · DevTools & Debug · Next.js
| Tópico | O mínimo |
|---|---|
| Map / Set | Map: chaves de qualquer tipo, ordem de inserção, .get/.set/.has/.size. Set: valores únicos — [...new Set(arr)] deduplica |
| JSON | JSON.stringify(o, null, 2) / JSON.parse. Perde undefined, funções, Date vira string, Map/Set viram {}. Lança em ciclo |
| Template literals | `${expr}`, multilinha, tagged templates |
| Iteradores / geradores | Protocolo Symbol.iterator (o que for...of/spread usam). function* + yield gera valores sob demanda |
| Regex | /padrão/flags · str.match/matchAll/replace/replaceAll · flags g i m s u. Grupos nomeados (?<ano>\d{4}) |
| Datas | Date é ruim; use Intl.DateTimeFormat/Intl.NumberFormat para exibir, ou Temporal (novo) / date-fns / Day.js |
| Números | Number.isInteger, toFixed (retorna string!), parseInt(x, 10) (sempre a base), Math.round/floor/ceil/trunc |
| Strings | trim, padStart, split, slice, at(-1), includes, replaceAll |
| Mutabilidade | Em frameworks reativos: nunca mutar state — sempre criar novo (spread, toSorted, with) |
| Strict mode | Módulos e classes já são strict. Pega erros silenciosos |
| DOM (1 frase) | document.querySelector, el.addEventListener, el.textContent/classList/dataset. Nunca innerHTML com dado do usuário (XSS). Depurar: → DevTools & Debug |
| Node vs browser | Sem window/document no Node; sem require/fs no browser. fetch existe nos dois hoje |
| TypeScript | É JS + tipos. Se o projeto é sério, provavelmente é TS. → Full Stack com TypeScript & Next.js |
✔️ Auto-checagem
Como deduplicar um array? O que JSON.stringify perde? Diferença entre Map e objeto simples. O que é XSS e como o innerHTML se relaciona? Por que parseInt(x) pode surpreender sem a base?
Checklist final dos fundamentos de JavaScript
Se você marca todos de cabeça, tem o básico. Onde travar, volte à seção — e à apostila completa se a dúvida for de fundo.
- os 7 primitivos, os 8 valores falsy, e por que
===sempre - testar
NaNcorretamente e a diferençanull/undefined - usar
const/let, o que é TDZ, e nunca usarvar - explicar e escrever uma closure com estado privado
- as 4 regras de
thise por que arrow não temthispróprio - destructuring, spread/rest,
?.e??(e por que??≠||) - que spread/
assignsão rasos e usarstructuredClonepara profundo map/filter/reduce/find/some/everye quais métodos mutam- que
sort()sem comparador ordena como string e muta - quando usar
for...ofem vez deforEach(break, await) - o event loop (microtask vs macrotask) em uma frase
Promise,async/await,try/catchem asyncPromise.allvsallSettledvsracevsany; paralelo vs sequencial- por que
forEach(async …)não espera nada class,extends/super,#privado,static, getters — e que é açúcar de protótipoimport/export(named vs default), ESM vs CJS,import()dinâmico- lançar
Error(nunca string), erro custom,Error.cause,finally - o perigo de engolir erro e de unhandled rejection
Map/Set, o queJSON.stringifyperde, template literals- não mutar state em framework reativo; não pôr dado do usuário em
innerHTML
Aprofundamento por tema: JavaScript Fullstack (linguagem completa, DOM, ferramentas) · Full Stack com TypeScript & Next.js (tipos, React Server Components) · Next.js · DevTools & Debug (inspeção e profiling) · Aceleração de Código com IA (fluxo assistido).