Cheatsheet JavaScript
Linguagem de programação para web e aplicações
JavaScript
Básico
Declaração de Variáveis
let nome = "Ana"; // mutável, escopo de bloco
const PI = 3.14159; // constante, não reatribuível
var antigo = "evitar"; // escopo de função (legacy)
// let pode ser reatribuído
nome = "Maria";
// const não pode ser reatribuído
// PI = 3; // TypeError!
// const com objetos: a referência é fixa
const user = { nome: "João" };
user.nome = "Pedro"; // OK - muta o conteúdo
// user = {}; // TypeError!Use const por padrão e let quando precisar reatribuir. Evite var — tem escopo de função e causa bugs com hoisting. const não impede mutação de objetos, apenas reatribuição da referência.
Truthy e Falsy
// Valores FALSY (6 no total):
false, 0, "", null, undefined, NaN
// Tudo o resto é TRUTHY:
true, 1, -1, "texto", [], {}, "0", "false"
// Exemplos práticos
if ("") { } // não executa (falsy)
if ("texto") { } // executa (truthy)
if ([]) { } // executa! (array vazio é truthy)
if ({}) { } // executa! (objeto vazio é truthy)
// Verificar booleano real
Boolean(""); // false
Boolean("oi"); // true
!!0; // false (dupla negação)
!!"texto"; // true
// Uso comum: valor default
let nome = input || "Anónimo";JavaScript tem 6 valores falsy: false, 0, "", null, undefined e NaN. Todo o resto é truthy, incluindo arrays e objetos vazios. Use !! para converter para booleano real.
Destructuring
// Arrays
const [a, b, c] = [1, 2, 3];
const [x, , z] = [1, 2, 3]; // pula índice 1
const [first, ...rest] = [1, 2, 3, 4];
// Default values
const [nome = "Anónimo"] = [];
// Objetos
const { name, age } = { name: "Ana", age: 30 };
const { name: n, age: a2 } = { name: "Ana", age: 30 };
// renomeia: n = "Ana", a2 = 30
// Nested
const { addr: { city } } = { addr: { city: "Porto" } };
// Em parâmetros de função
function mostrar({ nome, idade }) {
console.log(`${nome}, ${idade}`);
}
mostrar({ nome: "Ana", idade: 30 });
// Trocar variáveis
let x = 1, y = 2;
[x, y] = [y, x]; // x=2, y=1Destructuring extrai valores de arrays ou propriedades de objetos em variáveis. Suporta defaults, renomeação ({ name: n }), nesting e rest. Muito usado em parâmetros de funções.
typeof e instanceof
// typeof: retorna string com o tipo
typeof "texto"; // "string"
typeof 42; // "number"
typeof true; // "boolean"
typeof undefined; // "undefined"
typeof {}; // "object"
typeof []; // "object" (não distingue!)
typeof null; // "object" (bug!)
typeof function(){};// "function"
typeof Symbol(); // "symbol"
// instanceof: verifica protótipo
[] instanceof Array; // true
[] instanceof Object; // true
new Date() instanceof Date; // true
// Verificar array corretamente
Array.isArray([1,2]); // true
Array.isArray({}); // false
// Verificar null
const isNull = val === null;
const isNil = val == null; // null OU undefinedtypeof retorna o tipo como string mas falha com arrays e null. Use Array.isArray() para arrays e === null para null. instanceof verifica a cadeia de protótipos.
Tipos Primitivos
// 7 tipos primitivos
let str = "texto"; // string
let num = 42; // number
let big = 9007199254740991n; // bigint
let bool = true; // boolean
let undef = undefined; // undefined
let nulo = null; // null (objeto)
let sym = Symbol("id"); // symbol
// Verificar tipo
typeof str; // "string"
typeof num; // "number"
typeof bool; // "boolean"
typeof undef; // "undefined"
typeof nulo; // "object" (bug histórico!)
typeof sym; // "symbol"
typeof big; // "bigint"JavaScript tem 7 tipos primitivos. O typeof null retorna "object" — é um bug histórico da linguagem. Use === null para verificar null explicitamente.
Conversão de Tipos
// String → Number
Number("42"); // 42
parseInt("42px"); // 42
parseFloat("3.14"); // 3.14
+"42"; // 42 (unário)
// Number → String
String(42); // "42"
(42).toString(); // "42"
`${42}`; // "42"
// → Boolean
Boolean(1); // true
Boolean(""); // false
!!0; // false
// Coerção implícita (evitar!)
"5" + 3; // "53" (concatena!)
"5" - 3; // 2 (converte!)
true + 1; // 2
[] + {}; // "[object Object]"
// Verificar NaN
isNaN(NaN); // true
Number.isNaN(NaN); // true (mais seguro)Use Number(), parseInt() ou o unário + para converter strings em números. Cuidado com coerção implícita: "5" + 3 concatena ("53") mas "5" - 3 converte (2). Prefira Number.isNaN() em vez de isNaN().
console.log Essencial
// Básico
console.log("Valor:", 42);
console.warn("Aviso!");
console.error("Erro!");
console.info("Info");
// Formatação CSS
console.log("%c Texto azul", "color: blue");
// Tabela (arrays/objetos)
console.table([{ a: 1, b: 2 }, { a: 3, b: 4 }]);
// Objeto com profundidade
console.dir(obj, { depth: null });
// Agrupar
console.group("Grupo");
console.log("dentro");
console.groupEnd();
// Assert
console.assert(1 === 2, "1 não é 2!");Além de console.log(), use console.table() para arrays/objetos, console.dir() para inspecionar estrutura e console.group() para organizar logs relacionados.
Operadores de Comparação
// == vs === (SEMPRE use ===) 5 == "5"; // true (coerção de tipo!) 5 === "5"; // false (sem coerção) null == undefined; // true null === undefined; // false // Operadores relacionais 10 > 5; // true 10 <= 10; // true "a" < "b"; // true (ordem alfabética) // Operadores lógicos true && false; // false (AND) true || false; // true (OR) !true; // false (NOT) // Nullish coalescing (??) let val = null ?? "default"; // "default" let zero = 0 ?? "default"; // 0 (não é null!)
Sempre use === e !== em vez de == e != para evitar coerção implícita. O operador ?? (nullish) só ativa com null ou undefined, ao contrário de || que também ativa com 0 e "".
Optional Chaining (?.)
const user = {
nome: "Ana",
endereco: {
rua: "Av. Central",
cidade: "Lisboa"
}
};
// Sem optional chaining (verbose)
const cidade = user && user.endereco && user.endereco.cidade;
// Com optional chaining
const cidade2 = user?.endereco?.cidade; // "Lisboa"
const pais = user?.endereco?.pais; // undefined (sem erro!)
// Com métodos
const upper = user?.getNome?.(); // undefined se não existir
// Com arrays
const arr = [1, 2, 3];
arr?.[0]; // 1
arr?.[10]; // undefined
// Combinar com nullish
const nome = user?.nome ?? "Anónimo";O ?. (optional chaining) acede a propriedades sem erro se o objeto for null/undefined. Retorna undefined em vez de lançar TypeError. Combine com ?? para valores default.
console — Performance e Contagem
// Medir tempo
console.time("operação");
// ... código ...
console.timeEnd("operação"); // "operação: 2.5ms"
// Contador
console.count("click"); // "click: 1"
console.count("click"); // "click: 2"
console.countReset("click");
// Trace (call stack)
function a() { b(); }
function b() { console.trace(); }
a(); // mostra a pilha de chamadas
// debugger: pausa no DevTools
function calcular(x) {
debugger; // breakpoint manual
return x * 2;
}console.time()/timeEnd() mede performance. console.count() conta chamadas. console.trace() mostra a pilha de chamadas. debugger; cria um breakpoint no código.
Template Literals
const nome = "Ana";
const idade = 30;
// Interpolação com crase
const msg = `Olá, ${nome}! Tens ${idade} anos.`;
// Expressões dentro
const total = `Total: ${2 + 3 * 4}€`; // "Total: 14€"
// Multi-linha
const html = `
<div>
<h1>${nome}</h1>
<p>Idade: ${idade}</p>
</div>
`;
// Função dentro
const upper = `Nome: ${nome.toUpperCase()}`;
// Ternário dentro
const status = `${idade >= 18 ? "Adulto" : "Menor"}`;Template literals usam crase ` e permitem interpolação com ${expressão}. Suportam multi-linha sem \n e aceitam qualquer expressão JavaScript dentro de ${}.
Spread e Rest (...)
// SPREAD: expandir elementos
const arr1 = [1, 2, 3];
const arr2 = [...arr1, 4, 5]; // [1,2,3,4,5]
const obj1 = { a: 1, b: 2 };
const obj2 = { ...obj1, c: 3 }; // {a:1, b:2, c:3}
// Copiar (shallow copy)
const copia = [...arr1];
const objCopia = { ...obj1 };
// REST: recolher argumentos
function soma(...nums) {
return nums.reduce((a, b) => a + b, 0);
}
soma(1, 2, 3, 4); // 10
// Destructuring com rest
const [first, ...resto] = [1, 2, 3, 4];
// first = 1, resto = [2,3,4]
const { a, ...rest } = { a: 1, b: 2, c: 3 };
// a = 1, rest = {b:2, c:3}O operador ... tem dois usos: spread expande arrays/objetos e rest recolhe argumentos restantes. Cria cópias rasas (shallow) — objetos aninhados partilham referência.
Operador Ternário
// Sintaxe: condição ? valorSeTrue : valorSeFalse
const idade = 20;
const status = idade >= 18 ? "Adulto" : "Menor";
// Encadeado (evitar mais de 2 níveis)
const nota = 15;
const resultado = nota >= 18 ? "Excelente"
: nota >= 14 ? "Bom"
: nota >= 10 ? "Suficiente"
: "Insuficiente";
// Em JSX/templates
// {isAdmin ? <AdminPanel /> : <UserPanel />}
// Com nullish para defaults
const nome = user?.nome ?? "Anónimo";
// Atribuição condicional
let msg;
if (isAdmin) msg = "Bem-vindo admin";
else msg = "Bem-vindo";
// Equivalente:
const msg2 = isAdmin ? "Bem-vindo admin" : "Bem-vindo";O operador ternário condição ? a : b é uma expressão condicional compacta. Ideal para atribuições simples. Evite encadear mais de 2 níveis — use if/else para lógica complexa.
Strings
Busca e Verificação
const str = "Olá Mundo JavaScript";
str.length; // 20
str.indexOf("Mundo"); // 4
str.lastIndexOf("a"); // 17
str.includes("Mundo"); // true
str.startsWith("Olá"); // true
str.endsWith("Script"); // true
str.search(/mundo/i); // 4 (regex)
// match (retorna matches)
"2024-01-15".match(/\d+/g); // ["2024","01","15"]
// at() - índice negativo
"JavaScript".at(-1); // "t"
"JavaScript".at(-6); // "S"indexOf() retorna a posição (ou -1). includes(), startsWith() e endsWith() retornam boolean. at(-1) acede ao último caractere sem calcular o índice.
Unicode e Caracteres
// Código Unicode
"A".charCodeAt(0); // 65
String.fromCharCode(65); // "A"
// Code points (emoji)
"😀".codePointAt(0); // 128512
String.fromCodePoint(128512); // "😀"
// Iterar com for...of (respeita Unicode)
for (const char of "Olá 😀") {
console.log(char);
}
// Normalização
"café".normalize("NFC");
// Escape
"linha1\nlinha2"; // nova linha
"tab\taqui"; // tab
"aspas \"aqui\""; // aspas
// String.raw (sem escape)
String.raw`C:\novo\pasta`; // "C:\novo\pasta"
// Comparação locale
"a".localeCompare("b"); // -1
"ã".localeCompare("a"); // 1Use for...of para iterar strings com emoji (respeita surrogate pairs). String.raw ignora sequências de escape. localeCompare() compara strings com suporte a acentos.
Transformação de Strings
const str = "Olá Mundo JavaScript";
str.toUpperCase(); // "OLÁ MUNDO JAVASCRIPT"
str.toLowerCase(); // "olá mundo javascript"
str.slice(4, 9); // "Mundo"
str.substring(4, 9); // "Mundo"
str.replace("Mundo", "JS"); // "Olá JS JavaScript"
str.replaceAll("a", "o"); // "Olá Mundo JovaScript"
str.trim(); // remove espaços nas pontas
str.repeat(2); // repete a string
str.charAt(0); // "O"
// concat
"Olá".concat(" ", "Mundo"); // "Olá Mundo"Strings são imutáveis — os métodos retornam novas strings. slice() aceita índices negativos, replace() só substitui a primeira ocorrência (use replaceAll() para todas).
localeCompare e Normalização
// Comparação com locale
"a".localeCompare("b"); // -1
"ã".localeCompare("a", "pt"); // 1 (depois)
"Água".localeCompare("banana", "pt"); // -1
// Ordenar com acentos
["ação", "Água", "banana"].sort(
(a, b) => a.localeCompare(b, "pt")
);
// ["Água", "ação", "banana"]
// Normalização Unicode
"café".normalize("NFC"); // forma composta
"café".normalize("NFD"); // forma decomposta
// Verificar igualdade visual
const s1 = "\u00E9"; // é (composto)
const s2 = "e\u0301"; // é (decomposto)
s1 === s2; // false!
s1.normalize() === s2.normalize(); // truelocaleCompare() compara strings respeitando o idioma e acentos. normalize() uniformiza representações Unicode — essencial para comparar strings com acentos de fontes diferentes.
split, padStart e search
// split: string → array
"a,b,c".split(","); // ["a","b","c"]
"olá mundo".split(" "); // ["olá","mundo"]
"abc".split(""); // ["a","b","c"]
// join: array → string
["a","b","c"].join("-"); // "a-b-c"
// padStart / padEnd
"5".padStart(3, "0"); // "005"
"42".padEnd(5, "."); // "42..."
// search (com regex)
"Olá Mundo".search(/mundo/i); // 4
// match (retorna matches)
"2024-01-15".match(/\d+/g); // ["2024","01","15"]
// at() - índice negativo
"JavaScript".at(-1); // "t"
"JavaScript".at(-6); // "S"
// concat
"Olá".concat(" ", "Mundo"); // "Olá Mundo"split() divide uma string em array por delimitador. padStart()/padEnd() preenchem até um tamanho. at(-1) acede ao último caractere sem calcular o índice.
Regex Básico
// Criação
const re1 = /padrão/gi;
const re2 = new RegExp("padrão", "gi");
// Flags: g (global), i (case-insensitive), m (multiline)
// Testar
/^\d+$/.test("12345"); // true
/^\d+$/.test("12a45"); // false
// Extrair
const email = "ana@mail.com";
email.match(/(\w+)@(\w+)/);
// [0]="ana@mail", [1]="ana", [2]="mail"
// Substituir
"2024-01-15".replace(/-/g, "/"); // "2024/01/15"
// Metacaracteres comuns
// \d = dígito, \w = palavra, \s = espaço
// . = qualquer, ^ = início, $ = fim
// + = 1+, * = 0+, ? = 0 ou 1
// {n,m} = entre n e m
// Exemplo: validar email simples
const emailRe = /^[\w.]+@[\w]+\.[\w]{2,}$/;
emailRe.test("ana@mail.com"); // trueRegex em JS usa /padrão/flags. .test() verifica se há match, .match() extrai grupos e .replace() substitui. Metacaracteres: \d (dígito), \w (palavra), ^/$ (início/fim).
Números e Math
Arredondamento e Potência
// Arredondamento Math.round(4.5); // 5 Math.floor(4.9); // 4 (para baixo) Math.ceil(4.1); // 5 (para cima) Math.trunc(4.9); // 4 (corta decimal) // Mínimo e máximo Math.max(1, 5, 3); // 5 Math.min(1, 5, 3); // 1 Math.max(...[1,5,3]); // 5 (spread) // Potência e raiz Math.pow(2, 10); // 1024 2 ** 10; // 1024 (operador) Math.sqrt(16); // 4 Math.cbrt(27); // 3 // Valor absoluto Math.abs(-5); // 5
Math.floor() arredonda para baixo, Math.ceil() para cima, Math.round() para o mais próximo. Use ** em vez de Math.pow() para potência. Math.max(...arr) com spread para arrays.
Sistemas Numéricos
// Binário (0b)
0b1010; // 10
0b11111111; // 255
// Octal (0o)
0o17; // 15
0o777; // 511
// Hexadecimal (0x)
0xFF; // 255
0x1A; // 26
// Separador visual (ES2021)
1_000_000; // 1000000
0xFF_FF; // 65535
// Converter bases
(255).toString(16); // "ff"
(255).toString(2); // "11111111"
(10).toString(8); // "12"
// Parse de outras bases
parseInt("ff", 16); // 255
parseInt("1010", 2); // 10Prefixos: 0b binário, 0o octal, 0x hexadecimal. toString(base) converte para string noutra base. parseInt(str, base) parseia de outra base. Underscores (1_000) melhoram legibilidade.
Aleatório e Constantes
// Aleatório
Math.random(); // 0 a 0.999...
Math.floor(Math.random() * 10); // 0 a 9
// Inteiro entre min e max (inclusivo)
function aleatorio(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
aleatorio(1, 6); // 1 a 6 (dado)
// Constantes
Math.PI; // 3.14159...
Math.E; // 2.71828...
Math.SQRT2; // 1.41421...
// Arredondar com decimais
function roundDec(num, casas) {
const f = 10 ** casas;
return Math.round(num * f) / f;
}
roundDec(3.14159, 2); // 3.14Math.random() retorna um float entre 0 e 1. Math.floor(Math.random() * n) gera inteiros de 0 a n-1. Math.PI e Math.E são constantes. Para casas decimais, multiplique, arredonde e divida.
Formatação de Números
const num = 1234.5678;
// Casas decimais
num.toFixed(2); // "1234.57" (string!)
num.toPrecision(4); // "1235"
// Locale (moeda, separadores)
num.toLocaleString("pt-PT");
// "1 234,568"
// Moeda
num.toLocaleString("pt-PT", {
style: "currency",
currency: "EUR"
}); // "1 234,57 €"
// Percentagem
(0.75).toLocaleString("pt-PT", {
style: "percent"
}); // "75%"
// Notação científica
(1234567).toExponential(2); // "1.23e+6"
// parseInt / parseFloat
parseInt("42px"); // 42
parseFloat("3.14em"); // 3.14
parseInt("0xFF", 16); // 255 (hex)toFixed() retorna string — use Number() ou + para converter de volta. toLocaleString() formata com separadores e moeda do locale. parseInt() aceita base como 2º argumento.
Number: Métodos Estáticos
// Verificação
Number.isInteger(42); // true
Number.isInteger(4.5); // false
Number.isFinite(Infinity); // false
Number.isNaN(NaN); // true
Number.isNaN("42"); // false (sem coerção!)
// Limites
Number.MAX_SAFE_INTEGER; // 9007199254740991
Number.MIN_SAFE_INTEGER; // -9007199254740991
Number.MAX_VALUE; // 1.7976931348623157e+308
Number.EPSILON; // 2.220446049250313e-16
// Comparação de floats
0.1 + 0.2 === 0.3; // false!
Math.abs(0.1 + 0.2 - 0.3) < Number.EPSILON; // true
// BigInt (números enormes)
const big = 9007199254740993n;
big + 1n; // 9007199254740994n
// big + 1; // TypeError! (misturar tipos)Number.isNaN() não faz coerção (ao contrário de isNaN() global). Floats têm imprecisão: 0.1 + 0.2 !== 0.3. Use BigInt (sufixo n) para inteiros acima de MAX_SAFE_INTEGER.
Arrays
Criar e Aceder
// Criação
const arr = [1, 2, 3];
const arr2 = new Array(5); // [empty x 5]
const arr3 = Array.of(1, 2, 3);
const arr4 = Array.from("abc"); // ["a","b","c"]
const arr5 = Array.from({length: 5}, (_, i) => i);
// [0, 1, 2, 3, 4]
// Acesso
arr[0]; // 1
arr.at(-1); // 3 (último!)
arr.length; // 3
// Verificar
arr.includes(2); // true
arr.indexOf(2); // 1
arr.findIndex(x => x > 1); // 1
// Preencher
const filled = new Array(3).fill(0); // [0,0,0]
// Sequência
[...Array(5).keys()]; // [0,1,2,3,4]Array.from() converte iteráveis em arrays. at(-1) acede ao último elemento sem arr[arr.length-1]. Array.from({length: n}, fn) cria arrays com valores gerados.
find, some e every
const users = [
{ nome: "Ana", idade: 25 },
{ nome: "Pedro", idade: 30 },
{ nome: "Maria", idade: 35 },
];
// find: primeiro que satisfaz
users.find(u => u.idade > 28);
// { nome: "Pedro", idade: 30 }
// findIndex: índice do primeiro
users.findIndex(u => u.nome === "Maria"); // 2
// some: ALGUM satisfaz?
users.some(u => u.idade > 30); // true
// every: TODOS satisfazem?
users.every(u => u.idade > 20); // true
users.every(u => u.idade > 30); // false
// includes (valor primitivo)
[1, 2, 3].includes(2); // true
// findLast (ES2023)
users.findLast(u => u.idade > 28);
// { nome: "Maria", idade: 35 }find() retorna o primeiro elemento que satisfaz a condição. some() verifica se algum passa, every() se todos passam. findLast() procura do fim para o início.
Adicionar e Remover
const arr = [1, 2, 3]; // Adicionar arr.push(4); // [1,2,3,4] (fim) arr.unshift(0); // [0,1,2,3,4] (início) // Remover arr.pop(); // remove último → 4 arr.shift(); // remove primeiro → 0 // splice: remover/inserir em posição arr.splice(1, 2); // remove 2 desde índice 1 arr.splice(1, 0, 9, 8); // insere 9,8 no índice 1 // slice: copiar parte (não muta) arr.slice(1, 3); // [2, 3] arr.slice(-2); // últimos 2 // concat (não muta) [1,2].concat([3,4]); // [1,2,3,4] [...[1,2], ...[3,4]]; // [1,2,3,4] (spread) // flat: achatar [1, [2, [3]]].flat(); // [1, 2, [3]] [1, [2, [3]]].flat(2); // [1, 2, 3] [1, [2, [3]]].flat(Infinity); // [1, 2, 3]
push/pop operam no fim, unshift/shift no início. splice() muta o array original; slice() retorna cópia sem mutar. flat(Infinity) achata completamente.
Ordenação
// sort() MUTA o array original!
const nums = [10, 5, 40, 25];
// Numérico crescente
[...nums].sort((a, b) => a - b);
// [5, 10, 25, 40]
// Numérico decrescente
[...nums].sort((a, b) => b - a);
// [40, 25, 10, 5]
// Strings (alfabético)
["banana","apple","cherry"].sort();
// ["apple", "banana", "cherry"]
// Objetos por propriedade
const users = [{n:"Ana",i:25},{n:"Pedro",i:20}];
users.sort((a, b) => a.i - b.i);
// toSorted (ES2023 - não muta!)
const sorted = nums.toSorted((a, b) => a - b);
// nums permanece [10, 5, 40, 25]
// Locale compare (acentos)
["ação","banana","Água"].sort(
(a, b) => a.localeCompare(b, "pt")
);sort() muta o array original — use [...arr].sort() ou toSorted() (ES2023) para não mutar. Sem comparador, ordena como strings ("40" < "5"). Use localeCompare() para acentos.
map e filter
const nums = [1, 2, 3, 4, 5];
// map: transforma cada elemento
const dobro = nums.map(n => n * 2);
// [2, 4, 6, 8, 10]
// filter: mantém os que passam no teste
const pares = nums.filter(n => n % 2 === 0);
// [2, 4]
// map com índice
["a","b","c"].map((val, i) => `${i}:${val}`);
// ["0:a", "1:b", "2:c"]
// Encadear
const resultado = nums
.filter(n => n > 2)
.map(n => n * 10);
// [30, 40, 50]map() transforma cada elemento e retorna novo array. filter() seleciona os que passam no teste. Ambos não mutam o original. Encadeie para pipelines de transformação.
forEach, for...of e entries
const arr = ["a", "b", "c"];
// forEach (não retorna nada)
arr.forEach((val, i) => {
console.log(i, val);
});
// for...of (permite break/continue)
for (const val of arr) {
if (val === "b") break;
console.log(val);
}
// entries (índice + valor)
for (const [i, val] of arr.entries()) {
console.log(i, val);
}
// keys / values
[...arr.keys()]; // [0, 1, 2]
[...arr.values()]; // ["a", "b", "c"]
// for tradicional (performance)
for (let i = 0; i < arr.length; i++) {
console.log(arr[i]);
}
// flatMap (map + flat(1))
[[1,2],[3,4]].flatMap(a => a.map(x => x * 2));
// [2, 4, 6, 8]forEach() não permite break — use for...of quando precisar parar a iteração. entries() dá índice + valor. flatMap() é map() + flat(1) combinados.
reduce — Acumulador
const nums = [1, 2, 3, 4, 5];
// Soma
const soma = nums.reduce((acc, n) => acc + n, 0);
// 15
// Reduce para objeto (agrupar)
const grouped = [6.1, 4.2, 6.3].reduce((acc, n) => {
const key = Math.floor(n);
acc[key] = (acc[key] || 0) + 1;
return acc;
}, {}); // {4: 1, 6: 2}
// Pipeline completo
const total = nums
.filter(n => n > 2)
.map(n => n * 10)
.reduce((acc, n) => acc + n, 0);
// 120
// flatMap (map + flat(1))
[[1,2],[3,4]].flatMap(a => a.map(x => x * 2));
// [2, 4, 6, 8]reduce() acumula todos os elementos num único valor. O 2º argumento é o valor inicial do acumulador. Use para somar, agrupar ou transformar em objeto. flatMap() é map() + flat(1) combinados.
Métodos ES2023 (Não-Mutáveis)
const arr = [3, 1, 4, 1, 5]; // toSorted (não muta!) const ordenado = arr.toSorted((a, b) => a - b); // [1, 1, 3, 4, 5] | arr inalterado // toReversed (não muta!) const invertido = arr.toReversed(); // [5, 1, 4, 1, 3] // toSpliced (não muta!) const sem2 = arr.toSpliced(1, 2); // [3, 1, 5] | remove 2 desde índice 1 // with (substituir por índice) const trocado = arr.with(0, 99); // [99, 1, 4, 1, 5] // findLast / findLastIndex arr.findLast(n => n < 4); // 1 arr.findLastIndex(n => n < 4); // 3
ES2023: toSorted(), toReversed(), toSpliced() e with() retornam novos arrays sem mutar o original. findLast() procura do fim para o início.
Objetos
Criar e Manipular Objetos
// Literal
const obj = { nome: "Ana", idade: 30 };
// Acesso
obj.nome; // "Ana"
obj["idade"]; // 30
// Adicionar/modificar
obj.email = "ana@mail.com";
obj.idade = 31;
// Remover
delete obj.email;
// Verificar
"nome" in obj; // true
obj.hasOwnProperty("nome"); // true
// Chaves, valores, entradas
Object.keys(obj); // ["nome", "idade"]
Object.values(obj); // ["Ana", 31]
Object.entries(obj); // [["nome","Ana"],["idade",31]]
// Iterar
for (const [key, val] of Object.entries(obj)) {
console.log(key, val);
}Objetos são coleções de pares chave-valor. Object.keys(), Object.values() e Object.entries() retornam arrays iteráveis. delete remove uma propriedade.
JSON
const obj = { nome: "Ana", idade: 30, ativo: true };
// Objeto → JSON string
const json = JSON.stringify(obj);
// '{"nome":"Ana","idade":30,"ativo":true}'
// Formatado (pretty print)
JSON.stringify(obj, null, 2);
// Com filtro de chaves
JSON.stringify(obj, ["nome", "idade"]);
// JSON string → Objeto
const parsed = JSON.parse(json);
parsed.nome; // "Ana"
// Com reviver (transformar valores)
JSON.parse(json, (key, val) => {
return key === "idade" ? val + 1 : val;
});
// Cuidado: não suporta
// undefined, functions, Symbol, Date (vira string)
JSON.stringify(new Date()); // "2024-01-15T..."JSON.stringify() converte objeto em string JSON. JSON.parse() faz o inverso. Não suporta undefined, funções ou Symbol. Datas viram strings ISO.
Object.assign e Freeze
// Merge (shallow)
const a = { x: 1 };
const b = { y: 2 };
const c = Object.assign({}, a, b); // {x:1, y:2}
const d = { ...a, ...b }; // idem (spread)
// Clonar (shallow)
const clone = { ...a };
const clone2 = Object.assign({}, a);
// Congelar (imutável)
const config = Object.freeze({ port: 3000 });
config.port = 8080; // ignorado (strict: erro)
config.port; // 3000
// Verificar
Object.isFrozen(config); // true
// Seal (não adiciona/remove, mas edita)
const sealed = Object.seal({ a: 1 });
sealed.a = 2; // OK
sealed.b = 3; // ignorado
// Comparar objetos
Object.is(NaN, NaN); // true (=== dá false!)Object.assign() e spread fazem merge shallow. Object.freeze() torna imutável (não adiciona, remove ou edita). Object.is() é como === mas trata NaN corretamente.
Computed Properties e fromEntries
// Computed property names
const campo = "nome";
const obj = { [campo]: "Ana", [campo + "2"]: "Maria" };
// { nome: "Ana", nome2: "Maria" }
// Chave dinâmica em método
const metodo = "saudar";
const pessoa = {
[metodo]() { return "Olá!"; }
};
pessoa.saudar(); // "Olá!"
// Object.fromEntries (inverso de entries)
const pares = [["nome", "Ana"], ["idade", 30]];
Object.fromEntries(pares);
// { nome: "Ana", idade: 30 }
// Transformar valores de objeto
const precos = { a: 10, b: 20, c: 30 };
const comIva = Object.fromEntries(
Object.entries(precos).map(([k, v]) => [k, v * 1.23])
);
// { a: 12.3, b: 24.6, c: 36.9 }Computed properties ([expressão]) permitem chaves dinâmicas. Object.fromEntries() é o inverso de Object.entries() — converte pares em objeto. Útil para transformar valores de objetos.
Getters e Setters
const pessoa = {
_nome: "Ana",
_idade: 30,
get nome() {
return this._nome.toUpperCase();
},
set nome(val) {
if (val.length < 2) throw new Error("Nome curto");
this._nome = val;
},
get info() {
return `${this._nome}, ${this._idade} anos`;
}
};
pessoa.nome; // "ANA" (getter)
pessoa.nome = "Maria"; // setter
pessoa.info; // "Maria, 30 anos"
// Object.defineProperty
Object.defineProperty(pessoa, "id", {
value: 123,
writable: false,
enumerable: false
});Getters (get) e setters (set) permitem controlar acesso a propriedades. São acedidos como propriedades normais (sem parênteses). Object.defineProperty() define atributos como writable e enumerable.
Map e Set
// Map: objeto com chaves de qualquer tipo
const map = new Map();
map.set("nome", "Ana");
map.set(42, "número");
map.set({id: 1}, "objeto");
map.get("nome"); // "Ana"
map.has(42); // true
map.size; // 3
map.delete(42);
// Iterar Map
for (const [key, val] of map) {
console.log(key, val);
}
// Set: coleção de valores únicos
const set = new Set([1, 2, 2, 3, 3]);
set.size; // 3 (duplicados removidos!)
set.add(4);
set.has(2); // true
set.delete(1);
// Remover duplicados de array
const unique = [...new Set([1,1,2,3,3])];
// [1, 2, 3]Map aceita chaves de qualquer tipo (objetos, números) e mantém ordem de inserção. Set guarda valores únicos. Use [...new Set(arr)] para remover duplicados de um array.
Funções
Arrow Functions
// Tradicional
function soma(a, b) {
return a + b;
}
// Arrow function
const soma2 = (a, b) => a + b;
// Um parâmetro (parênteses opcionais)
const dobro = n => n * 2;
// Corpo com múltiplas linhas
const calcular = (a, b) => {
const resultado = a * b;
return resultado + 1;
};
// Sem parâmetros
const ola = () => "Olá!";
// Retorno de objeto (parênteses!)
const criar = (nome) => ({ nome, ativo: true });
// Diferença: this
// Arrow NÃO tem this próprio (herda do escopo)
const obj = {
nome: "Ana",
// ERRADO com arrow:
// falar: () => console.log(this.nome),
// CERTO com função normal:
falar() { console.log(this.nome); }
};Arrow functions (=>) têm sintaxe compacta e não têm this próprio — herdam do escopo envolvente. Para retornar objeto literal, envolva em parênteses: () => ({...}).
Métodos de Função
function saudar(saudacao, nome) {
return `${saudacao}, ${nome}!`;
}
// call: invoca com this e args separados
saudar.call(null, "Olá", "Ana");
// "Olá, Ana!"
// apply: invoca com this e array de args
saudar.apply(null, ["Olá", "Ana"]);
// "Olá, Ana!"
// bind: cria nova função com this fixo
const olaAna = saudar.bind(null, "Olá", "Ana");
olaAna(); // "Olá, Ana!"
// Uso prático: fixar this
const btn = document.querySelector("button");
btn.addEventListener("click",
this.handleClick.bind(this)
);
// Partial application
const multiply = (a, b) => a * b;
const double = multiply.bind(null, 2);
double(5); // 10call() e apply() invocam com this definido (diferem nos args: separados vs array). bind() cria uma nova função com this fixo — útil em event handlers.
Parâmetros Default e Rest
// Default parameters
function saudar(nome = "Mundo", pontuacao = "!") {
return `Olá, ${nome}${pontuacao}`;
}
saudar(); // "Olá, Mundo!"
saudar("Ana"); // "Olá, Ana!"
saudar("Ana", "."); // "Olá, Ana."
// Rest parameters
function soma(...nums) {
return nums.reduce((a, b) => a + b, 0);
}
soma(1, 2, 3); // 6
// arguments (legacy - evitar)
function legacy() {
console.log(arguments.length);
}
// Named parameters (via destructuring)
function criarUser({ nome, idade = 18, ativo = true }) {
return { nome, idade, ativo };
}
criarUser({ nome: "Ana", idade: 25 });Parâmetros default (= valor) ativam quando o argumento é undefined. Rest (...args) recolhe argumentos num array. Named parameters via destructuring são ideais para funções com muitas opções.
Recursão e IIFE
// Recursão: função que se chama a si mesma
function fatorial(n) {
if (n <= 1) return 1; // caso base
return n * fatorial(n - 1);
}
fatorial(5); // 120
// Recursão com acumulador (tail)
function soma(n, acc = 0) {
if (n === 0) return acc;
return soma(n - 1, acc + n);
}
soma(100); // 5050
// IIFE: Immediately Invoked Function Expression
(function() {
const privado = "não acessível fora";
console.log(privado);
})();
// IIFE com arrow (moderno)
(() => {
const config = { debug: true };
// setup inicial...
})();Recursão: função que se chama a si mesma — precisa sempre de um caso base. IIFE executa imediatamente e cria escopo privado. Útil para setup inicial e evitar poluição do escopo global.
Closures
// Closure: função que "lembra" do escopo onde foi criada
function contador() {
let count = 0;
return {
incrementar: () => ++count,
decrementar: () => --count,
valor: () => count
};
}
const c = contador();
c.incrementar(); // 1
c.incrementar(); // 2
c.valor(); // 2
// count não é acessível diretamente!
// Uso prático: função factory
function multiplicador(fator) {
return (n) => n * fator;
}
const dobro = multiplicador(2);
const triplo = multiplicador(3);
dobro(5); // 10
triplo(5); // 15
// Closure em loops (clássico)
for (let i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 100);
}
// 0, 1, 2 (let cria escopo por iteração)Uma closure é uma função que mantém acesso ao escopo onde foi criada, mesmo após esse escopo terminar. Permite dados privados e factories. Use let em loops para criar escopo por iteração.
Callbacks e Higher-Order
// Callback: função passada como argumento
function processar(arr, callback) {
return arr.map(callback);
}
processar([1,2,3], n => n * 2); // [2,4,6]
// Higher-order: recebe/retorna funções
function aplicar(fn, valor) {
return fn(valor);
}
aplicar(Math.sqrt, 16); // 4
// Composição
const pipe = (...fns) => (x) =>
fns.reduce((acc, fn) => fn(acc), x);
const transformar = pipe(
x => x * 2,
x => x + 1,
x => `Resultado: ${x}`
);
transformar(5); // "Resultado: 11"
// Debounce (callback adiado)
function debounce(fn, delay) {
let timer;
return (...args) => {
clearTimeout(timer);
timer = setTimeout(() => fn(...args), delay);
};
}Uma callback é uma função passada como argumento. Higher-order functions recebem ou retornam funções. pipe() compõe funções em sequência. debounce() atrasa execução até parar de chamar.
Controlo de Fluxo
if/else e switch
// if/else
if (idade >= 18) {
console.log("Adulto");
} else if (idade >= 12) {
console.log("Adolescente");
} else {
console.log("Criança");
}
// switch
switch (dia) {
case 1:
case 2:
case 3:
case 4:
case 5:
console.log("Útil");
break;
case 6:
case 7:
console.log("Fim de semana");
break;
default:
console.log("Inválido");
}
// switch com expressões
switch (true) {
case nota >= 18: console.log("Excelente"); break;
case nota >= 14: console.log("Bom"); break;
default: console.log("Suficiente");
}if/else para condições simples. switch para múltiplos valores — não esqueça o break! switch(true) permite comparar expressões como um if/else encadeado.
for, for...of e for...in
// for tradicional
for (let i = 0; i < 5; i++) {
console.log(i);
}
// for...of (arrays, strings, Map, Set)
for (const item of [1, 2, 3]) {
console.log(item);
}
// for...in (chaves de objetos)
for (const key in { a: 1, b: 2 }) {
console.log(key); // "a", "b"
}
// for...of com índice
for (const [i, val] of ["a","b","c"].entries()) {
console.log(i, val);
}for...of itera valores (arrays, strings, Map, Set). for...in itera chaves (objetos). Prefira for...of com .entries() para ter índice + valor em arrays.
while, break e continue
// while
let n = 0;
while (n < 5) {
n++;
}
// do...while (executa pelo menos 1x)
do {
n--;
} while (n > 0);
// break e continue
for (let i = 0; i < 10; i++) {
if (i === 3) continue; // pula 3
if (i === 7) break; // para no 7
console.log(i); // 0,1,2,4,5,6
}
// Label (loops aninhados)
outer: for (let i = 0; i < 3; i++) {
for (let j = 0; j < 3; j++) {
if (i === 1 && j === 1) break outer;
}
}while repete enquanto a condição for verdadeira. do...while executa pelo menos uma vez. break sai do loop, continue pula para a próxima iteração. Labels permitem sair de loops aninhados.
Operadores Lógicos Avançados
// Short-circuit evaluation
const nome = input || "Anónimo"; // OR: 1º truthy
const config = user && user.config; // AND: 1º falsy ou último
// Nullish coalescing (??)
const val = 0 ?? "default"; // 0 (não é null!)
const val2 = null ?? "default"; // "default"
// Logical assignment (ES2021)
let a = null;
a ??= "default"; // a = "default"
let b = 0;
b ||= 10; // b = 10 (0 é falsy)
b ??= 20; // b = 10 (0 não é null)
let c = { x: 1 };
c.x &&= 2; // c.x = 2 (x existe e é truthy)
// Encadeamento de comparações
// ERRADO: 1 < x < 10
// CERTO:
const inRange = x > 1 && x < 10;|| retorna o primeiro truthy, && o primeiro falsy ou o último. ?? só ativa com null/undefined. Operadores de atribuição lógica: ??=, ||=, &&=.
Datas e Tempo
Objeto Date
// Criar datas
const agora = new Date();
const data = new Date(2024, 0, 15); // 15 Jan 2024
const data2 = new Date("2024-01-15");
const data3 = new Date(2024, 0, 15, 14, 30, 0);
// Getters
agora.getFullYear(); // 2024
agora.getMonth(); // 0-11 (0 = Janeiro!)
agora.getDate(); // 1-31
agora.getDay(); // 0-6 (0 = Domingo)
agora.getHours(); // 0-23
agora.getMinutes(); // 0-59
agora.getTime(); // ms desde 1970
// Setters
data.setFullYear(2025);
data.setMonth(11); // Dezembro
// Timestamp
Date.now(); // ms atuais
// Comparar
const d1 = new Date("2024-01-01");
const d2 = new Date("2024-12-31");
d1 < d2; // truegetMonth() retorna 0-11 (0 = Janeiro!). Date.now() dá o timestamp em ms. Para comparar datas, use os operadores < e > diretamente.
Formatação de Datas
const data = new Date(2024, 0, 15, 14, 30);
// toLocaleDateString
data.toLocaleDateString("pt-PT");
// "15/01/2024"
data.toLocaleDateString("pt-PT", {
weekday: "long",
year: "numeric",
month: "long",
day: "numeric"
});
// "segunda-feira, 15 de janeiro de 2024"
// toLocaleTimeString
data.toLocaleTimeString("pt-PT");
// "14:30:00"
// ISO
data.toISOString();
// "2024-01-15T14:30:00.000Z"
// Diferença entre datas (em dias)
const d1 = new Date("2024-01-01");
const d2 = new Date("2024-01-15");
const diffDias = (d2 - d1) / (1000 * 60 * 60 * 24);
// 14toLocaleDateString() formata com locale. Subtração de datas dá milissegundos — divida por 1000*60*60*24 para dias. toISOString() retorna formato ISO 8601.
setTimeout e setInterval
// setTimeout: executa 1x após delay
const timer = setTimeout(() => {
console.log("Passou 2s");
}, 2000);
// Cancelar
clearTimeout(timer);
// setInterval: repete a cada X ms
const interval = setInterval(() => {
console.log("Tick");
}, 1000);
// Parar
clearInterval(interval);
// Contagem decrescente
let seg = 5;
const countdown = setInterval(() => {
console.log(seg--);
if (seg < 0) clearInterval(countdown);
}, 1000);
// requestAnimationFrame (60fps)
function animar() {
// ... desenhar ...
requestAnimationFrame(animar);
}
requestAnimationFrame(animar);setTimeout() executa uma vez após delay. setInterval() repete. Ambos retornam um ID para cancelar com clearTimeout()/clearInterval(). Use requestAnimationFrame() para animações.
Intl.DateTimeFormat e Relative Time
// Intl.DateTimeFormat (reutilizável)
const fmt = new Intl.DateTimeFormat("pt-PT", {
weekday: "long",
day: "numeric",
month: "long",
year: "numeric"
});
fmt.format(new Date());
// "sexta-feira, 15 de março de 2024"
// RelativeTimeFormat ("há 3 dias")
const rtf = new Intl.RelativeTimeFormat("pt", {
numeric: "auto"
});
rtf.format(-3, "day"); // "há 3 dias"
rtf.format(1, "month"); // "próximo mês"
rtf.format(-2, "hour"); // "há 2 horas"
// Diferença relativa
function tempoRelativo(data) {
const diff = data - Date.now();
const dias = Math.round(diff / 86400000);
return rtf.format(dias, "day");
}Intl.DateTimeFormat é reutilizável e mais rápido que toLocaleDateString() em loops. Intl.RelativeTimeFormat cria textos como "há 3 dias" ou "próximo mês". Suporta todos os locales.
DOM e Eventos
Selecionar Elementos
// Um elemento
const el = document.getElementById("app");
const el2 = document.querySelector(".card");
const el3 = document.querySelector("#app > p");
// Vários elementos
const todos = document.querySelectorAll(".item");
const porClasse = document.getElementsByClassName("item");
const porTag = document.getElementsByTagName("p");
// querySelectorAll retorna NodeList (estático)
// getElementsBy* retorna HTMLCollection (vivo)
todos.forEach(el => console.log(el));querySelector() aceita qualquer seletor CSS e retorna o primeiro. querySelectorAll() retorna todos como NodeList (tem forEach). getElementsBy* retorna HTMLCollection (atualiza em tempo real).
Delegação de Eventos
// Em vez de um listener por botão...
const lista = document.querySelector("#lista");
// Um listener no pai (delegação)
lista.addEventListener("click", (e) => {
const item = e.target.closest("li");
if (!item) return;
console.log("Clicou em:", item.textContent);
// Exemplo: remover item
if (e.target.matches(".remover")) {
item.remove();
}
});
// Funciona para elementos futuros (dinâmicos)
const novoLi = document.createElement("li");
novoLi.innerHTML = 'Novo <button class="remover">X</button>';
lista.appendChild(novoLi); // já tem listener!Delegação: um listener no pai captura eventos dos filhos via bubbling. Use e.target.closest() para encontrar o elemento pretendido. Funciona para elementos adicionados dinamicamente sem registar novos listeners.
MutationObserver
// Observar mudanças no DOM
const observer = new MutationObserver((mutations) => {
mutations.forEach(m => {
if (m.type === "childList") {
console.log("Filhos alterados:", m.addedNodes.length);
}
if (m.type === "attributes") {
console.log(`Atributo ${m.attributeName} mudou`);
}
});
});
// Configurar o que observar
observer.observe(document.body, {
childList: true, // adição/remoção de filhos
attributes: true, // mudanças de atributos
subtree: true, // incluir descendentes
characterData: true // mudanças de texto
});
// Parar de observar
observer.disconnect();MutationObserver deteta mudanças no DOM (filhos, atributos, texto). Substitui o antigo MutationEvent (mais performante). Útil para editores WYSIWYG, auto-save e deteção de mudanças.
Criar e Inserir Elementos
// Criar
const div = document.createElement("div");
div.textContent = "Olá";
div.classList.add("card");
div.id = "novo";
// Inserir
const pai = document.querySelector("#app");
pai.appendChild(div); // último filho
pai.prepend(div); // primeiro filho
pai.append(div, "texto"); // múltiplos
// Inserir relativo a outro elemento
const ref = document.querySelector(".ref");
ref.before(div); // antes de ref
ref.after(div); // depois de ref
ref.replaceWith(div); // substitui ref
// Remover
div.remove();createElement() cria o elemento, appendChild()/prepend() inserem no pai. before()/after() inserem relativo a um elemento. remove() elimina do DOM.
innerHTML vs textContent
const div = document.querySelector("#app");
// textContent: só texto (seguro)
div.textContent = "<b>Negrito</b>";
// Mostra: <b>Negrito</b> (literal)
// innerHTML: parseia HTML (cuidado XSS!)
div.innerHTML = "<b>Negrito</b>";
// Mostra: Negrito (formatado)
// insertAdjacentHTML (não limpa filhos)
div.insertAdjacentHTML("beforeend", "<p>Fim</p>");
div.insertAdjacentHTML("afterbegin", "<p>Inicio</p>");
// Performance: DocumentFragment
const frag = document.createDocumentFragment();
for (let i = 0; i < 1000; i++) {
const li = document.createElement("li");
li.textContent = i;
frag.appendChild(li);
}
div.appendChild(frag); // 1 reflowtextContent é seguro (não parseia HTML). innerHTML parseia mas é vulnerável a XSS. insertAdjacentHTML() insere sem limpar. DocumentFragment evita múltiplos reflows.
Manipular Classes e Estilos
const el = document.querySelector(".card");
// classList
el.classList.add("ativo", "visivel");
el.classList.remove("oculto");
el.classList.toggle("dark");
el.classList.contains("ativo"); // true
el.classList.replace("old", "new");
// Estilos inline
el.style.color = "red";
el.style.backgroundColor = "#333";
el.style.cssText = "color: red; font-size: 16px;";
// Ler estilos computados
const estilos = getComputedStyle(el);
estilos.fontSize; // "16px"
// Atributos
el.setAttribute("data-id", "42");
el.getAttribute("data-id"); // "42"
el.dataset.id; // "42" (data-*)classList gere classes sem sobrescrever. toggle() adiciona/remove. style define estilos inline. getComputedStyle() lê o CSS final. dataset acede a atributos data-*.
Formulários e Inputs
const form = document.querySelector("form");
const input = document.querySelector("#nome");
// Ler valores
input.value; // texto do input
input.checked; // checkbox/radio
input.files; // file input
// FormData (todos os campos)
const dados = new FormData(form);
dados.get("nome");
dados.append("extra", "valor");
// Submit com fetch
form.addEventListener("submit", async (e) => {
e.preventDefault();
const dados = new FormData(form);
const res = await fetch("/api", {
method: "POST",
body: dados
});
});
// Validação nativa
input.validity.valid; // true/false
input.checkValidity(); // dispara invalid
input.setCustomValidity("Erro!");FormData recolhe todos os campos do formulário. Use com fetch() para enviar. e.preventDefault() impede o submit padrão. input.validity dá acesso à validação nativa do browser.
Eventos — addEventListener
const btn = document.querySelector("#btn");
// Adicionar listener
btn.addEventListener("click", function(e) {
console.log(e.target); // elemento clicado
console.log(e.type); // "click"
console.log(e.clientX); // posição X
e.preventDefault(); // impede ação padrão
e.stopPropagation(); // impede bubbling
});
// Arrow function
btn.addEventListener("click", (e) => {
console.log("clicado!");
});
// Opções
btn.addEventListener("click", handler, {
once: true, // remove após 1ª execução
capture: true, // fase de captura
passive: true // não chama preventDefault
});
// Remover
btn.removeEventListener("click", handler);addEventListener() regista um handler. e.target é o elemento que originou o evento. preventDefault() impede a ação padrão. once: true auto-remove após a primeira execução.
IntersectionObserver (Lazy Load)
// Observar elementos ao entrar no viewport
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
entry.target.classList.add("visivel");
observer.unobserve(entry.target);
}
});
}, {
threshold: 0.1, // 10% visível
rootMargin: "50px" // margem extra
});
// Observar elementos
document.querySelectorAll(".lazy")
.forEach(el => observer.observe(el));
// Lazy load de imagens
const imgObs = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target;
img.src = img.dataset.src;
imgObs.unobserve(img);
}
});
});IntersectionObserver deteta quando elementos entram no viewport. Ideal para lazy loading, animações ao scroll e infinite scroll. threshold define a % visível para ativar. unobserve() para de observar.
Async e Promises
Promises — Básico
// Criar uma Promise
const promessa = new Promise((resolve, reject) => {
const sucesso = true;
if (sucesso) {
resolve("Dados prontos");
} else {
reject(new Error("Falhou"));
}
});
// Consumir
promessa
.then(resultado => console.log(resultado))
.catch(erro => console.error(erro))
.finally(() => console.log("Sempre executa"));
// Estados: pending → fulfilled | rejected
// Uma Promise resolve apenas 1 vezUma Promise tem 3 estados: pending, fulfilled, rejected. resolve() cumpre, reject() rejeita. .then() trata sucesso, .catch() erro, .finally() sempre executa.
Promise.all e allSettled
// Executar em paralelo
const [users, posts] = await Promise.all([
fetch("/api/users").then(r => r.json()),
fetch("/api/posts").then(r => r.json())
]);
// allSettled: espera todas (mesmo com erro)
const resultados = await Promise.allSettled([
fetch("/api/a"),
fetch("/api/b") // pode falhar
]);
resultados.forEach(r => {
if (r.status === "fulfilled") console.log(r.value);
else console.log(r.reason);
});Promise.all() espera todas e falha se uma falhar. Promise.allSettled() espera todas sem falhar — retorna status de cada uma. Use all() quando todas são obrigatórias.
Web Workers (Básico)
// worker.js (ficheiro separado)
self.onmessage = (e) => {
const resultado = e.data * 2;
self.postMessage(resultado);
};
// main.js
const worker = new Worker("worker.js");
worker.onmessage = (e) => {
console.log("Resultado:", e.data);
};
worker.postMessage(21); // envia dados
// Terminar
worker.terminate();
// Inline worker (sem ficheiro)
const blob = new Blob([`
self.onmessage = (e) => {
self.postMessage(e.data.toUpperCase());
};
`], { type: "application/javascript" });
const inline = new Worker(URL.createObjectURL(blob));Web Workers executam código numa thread separada (não bloqueia a UI). Comunique via postMessage()/onmessage. Ideal para cálculos pesados. terminate() encerra o worker.
async/await
// Função async retorna Promise
async function buscarDados() {
try {
const res = await fetch("/api/dados");
const dados = await res.json();
return dados;
} catch (erro) {
console.error("Erro:", erro);
throw erro;
}
}
// Chamar
buscarDados()
.then(dados => console.log(dados))
.catch(e => console.error(e));
// Em arrow functions
const buscar = async () => {
const res = await fetch("/api");
return res.json();
};
// IIFE async
(async () => {
const dados = await buscar();
console.log(dados);
})();async marca a função como assíncrona (retorna Promise). await pausa até a Promise resolver. Use try/catch para erros. Só pode usar await dentro de funções async (ou top-level em módulos).
Promise.race e any
// race: primeira a resolver (ou rejeitar)
const maisRapida = await Promise.race([
fetch("/api/servidor1"),
fetch("/api/servidor2")
]);
// any: primeira com sucesso (ignora erros)
const primeira = await Promise.any([p1, p2, p3]);
// Timeout com race
function comTimeout(promise, ms) {
const timeout = new Promise((_, reject) =>
setTimeout(() => reject(new Error("Timeout")), ms)
);
return Promise.race([promise, timeout]);
}
await comTimeout(fetch("/api"), 5000);Promise.race() retorna a primeira a resolver OU rejeitar. Promise.any() retorna a primeira com sucesso (ignora erros). Útil para timeouts e tentar múltiplos servidores.
Event Loop e Microtasks
console.log("1 - Síncrono");
setTimeout(() => {
console.log("2 - Macrotask (timeout)");
}, 0);
Promise.resolve().then(() => {
console.log("3 - Microtask (promise)");
});
queueMicrotask(() => {
console.log("4 - Microtask (queue)");
});
console.log("5 - Síncrono");
// Ordem: 1, 5, 3, 4, 2
// Síncrono → Microtasks → MacrotasksO Event Loop processa: 1) código síncrono, 2) microtasks (Promises, queueMicrotask), 3) macrotasks (setTimeout, eventos). Mesmo com delay 0, setTimeout executa por último.
fetch — GET e Leitura
// GET simples
const res = await fetch("https://api.exemplo.com/dados");
const dados = await res.json();
// Verificar status
if (!res.ok) {
throw new Error(`HTTP ${res.status}`);
}
// Headers e status
res.headers.get("content-type");
res.status; // 200, 404, 500...
// DELETE
await fetch("/api/1", { method: "DELETE" });fetch() retorna uma Promise. res.json() parseia o body. Verifique sempre res.ok (status 200-299) antes de usar os dados. res.status dá o código HTTP.
Encadeamento de Promises
// Encadear .then()
fetch("/api/user/1")
.then(res => res.json())
.then(user => fetch(`/api/posts/${user.id}`))
.then(res => res.json())
.then(posts => console.log(posts))
.catch(err => console.error(err));
// Equivalente com async/await (mais legível)
async function getPosts() {
const res = await fetch("/api/user/1");
const user = await res.json();
const res2 = await fetch(`/api/posts/${user.id}`);
return res2.json();
}
// Retornar valor vs Promise
Promise.resolve(42)
.then(n => n * 2) // 84
.then(n => Promise.resolve(n + 1)) // 85
.then(console.log);Cada .then() retorna uma nova Promise. Pode retornar um valor ou outra Promise. async/await é mais legível para operações sequenciais. Erros propagam até ao .catch().
Async Iterators (for await...of)
// Objeto com async iterator
const paginas = {
async *[Symbol.asyncIterator]() {
let page = 1;
while (true) {
const res = await fetch(`/api?page=${page}`);
const dados = await res.json();
if (!dados.length) return;
yield dados;
page++;
}
}
};
// Consumir com for await...of
for await (const items of paginas) {
console.log("Página:", items);
}
// Stream de resposta fetch
const res = await fetch("/api/grande");
const reader = res.body.getReader();
while (true) {
const { done, value } = await reader.read();
if (done) break;
console.log("Chunk:", value.length, "bytes");
}for await...of itera sobre async iterables. async *[Symbol.asyncIterator]() define um gerador assíncrono. Ideal para paginação, streams e leitura de ficheiros em chunks.
fetch — POST e Headers
// POST com JSON
const res = await fetch("/api/utilizadores", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": "Bearer token123"
},
body: JSON.stringify({ nome: "Ana", idade: 30 })
});
const criado = await res.json();
// PUT (atualizar)
await fetch("/api/1", {
method: "PUT",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ nome: "Maria" })
});
// POST com FormData (upload)
const form = new FormData();
form.append("ficheiro", fileInput.files[0]);
await fetch("/upload", { method: "POST", body: form });Para POST, defina Content-Type e use JSON.stringify() no body. Authorization envia tokens. Para uploads, use FormData sem definir header (o browser define automaticamente).
AbortController (Cancelar fetch)
const controller = new AbortController();
const { signal } = controller;
// Fetch com signal
const res = await fetch("/api/dados", { signal });
// Cancelar após 5s
const timeout = setTimeout(() => {
controller.abort();
}, 5000);
try {
const dados = await res.json();
clearTimeout(timeout);
} catch (e) {
if (e.name === "AbortError") {
console.log("Requisição cancelada");
}
}
// Cancelar em botão
const btn = document.querySelector("#cancelar");
btn.addEventListener("click", () => {
controller.abort();
});AbortController cancela requisições fetch(). Passe signal nas opções. controller.abort() cancela. O erro tem name === "AbortError". Útil para timeouts e cancelar requests ao navegar.
ES6+ Moderno
Modules (import/export)
// utils.js — Named exports
export const PI = 3.14159;
export function soma(a, b) { return a + b; }
export class Calculadora { /* ... */ }
// app.js — Named imports
import { PI, soma } from "./utils.js";
import { soma as add } from "./utils.js"; // alias
import * as utils from "./utils.js"; // namespace
utils.PI; // 3.14159
// Default export (1 por ficheiro)
// api.js
export default class Api { /* ... */ }
// Import default (qualquer nome)
import Api from "./api.js";
import MinhaApi from "./api.js"; // mesmo resultado
// Dynamic import (lazy loading)
const modulo = await import("./pesado.js");
modulo.funcao();export exporta, import importa. Named exports permitem vários por ficheiro. Default export só 1 por ficheiro. import() dinâmico carrega sob demanda (code splitting). Use .js no path.
WeakMap, WeakSet e Symbol
// Symbol: identificador único
const id = Symbol("id");
const obj = { [id]: 123 };
obj[id]; // 123
// Symbols bem conhecidos
const arr = [3, 1, 2];
arr[Symbol.iterator](); // iterador
// WeakMap: chaves fracas (GC pode limpar)
const cache = new WeakMap();
function processar(obj) {
if (cache.has(obj)) return cache.get(obj);
const resultado = /* cálculo pesado */ obj;
cache.set(obj, resultado);
return resultado;
}
// WeakSet: objetos únicos (fracos)
const vistos = new WeakSet();
vistos.add(elemento);
vistos.has(elemento); // trueSymbol cria identificadores únicos. WeakMap/WeakSet têm chaves fracas — o Garbage Collector pode limpar entradas se a chave for coletada. Ideais para caches e metadados privados.
Classes
class Animal {
// Campos privados (ES2022)
#energia = 100;
constructor(nome, som) {
this.nome = nome;
this.som = som;
}
falar() {
return `${this.nome} faz ${this.som}`;
}
// Getter/Setter
get energia() { return this.#energia; }
set energia(val) { this.#energia = Math.max(0, val); }
// Método estático
static criar(nome) {
return new Animal(nome, "...");
}
}
// Herança
class Cao extends Animal {
constructor(nome) {
super(nome, "Au au");
}
falar() {
return `${super.falar()}!`;
}
}class define classes. constructor() inicializa. #campo é privado. extends/super() para herança. get/set criam accessors. static pertence à classe, não à instância.
Top-level Await e using
// Top-level await (ES2022, em módulos)
// Não precisa de IIFE async!
const dados = await fetch("/api/config")
.then(r => r.json());
// Import dinâmico condicional
const modulo = process.env.DEBUG
? await import("./debug.js")
: await import("./producao.js");
// using (ES2024 - resource management)
// using declara recursos que são limpos automaticamente
function abrirFicheiro() {
return {
[Symbol.dispose]() {
console.log("Ficheiro fechado");
}
};
}
{
using ficheiro = abrirFicheiro();
// usar ficheiro...
} // Symbol.dispose() chamado automaticamenteTop-level await permite await fora de funções async (só em módulos ES). using (ES2024) declara recursos com limpeza automática via Symbol.dispose() — similar ao using do C# ou with do Python.
Generators e Iterators
// Generator function
function* contador(max) {
let i = 0;
while (i < max) {
yield i++;
}
}
const gen = contador(3);
gen.next(); // { value: 0, done: false }
gen.next(); // { value: 1, done: false }
gen.next(); // { value: 2, done: false }
gen.next(); // { value: undefined, done: true }
// Iterável com for...of
for (const n of contador(5)) {
console.log(n); // 0, 1, 2, 3, 4
}
// Lazy evaluation (infinito)
function* fibonacci() {
let [a, b] = [0, 1];
while (true) {
yield a;
[a, b] = [b, a + b];
}
}function* cria um generator. yield pausa e retorna valor. .next() retoma. São lazy — só calculam quando pedido. Ideais para sequências infinitas e pipelines de dados.
Proxy e Reflect
// Proxy: intercepta operações
const handler = {
get(target, prop) {
console.log(`Acedeu: ${prop}`);
return Reflect.get(target, prop);
},
set(target, prop, value) {
if (typeof value !== "number") {
throw new TypeError("Só números!");
}
return Reflect.set(target, prop, value);
}
};
const dados = new Proxy({ x: 1 }, handler);
dados.x; // log + 1
dados.x = 5; // OK
dados.x = "a"; // TypeError!
// Validação reativa
const state = new Proxy({ count: 0 }, {
set(t, p, v) {
Reflect.set(t, p, v);
render(); // re-renderiza
return true;
}
});Proxy intercepta operações (get, set, delete, etc.) num objeto. Reflect fornece os métodos padrão. Útil para validação, logging, reatividade e data binding. Base de frameworks como Vue.
Erros e Debug
try/catch/finally
try {
const dados = JSON.parse(texto);
if (!dados.nome) {
throw new Error("Campo 'nome' obrigatório");
}
} catch (erro) {
console.error("Tipo:", erro.name); // "Error"
console.error("Msg:", erro.message); // mensagem
console.error("Stack:", erro.stack); // trace
} finally {
console.log("Sempre executa");
// Fechar conexões, limpar recursos
}
// Em async/await
async function carregar() {
try {
const res = await fetch("/api");
return await res.json();
} catch (e) {
console.error("Falha:", e.message);
return null;
}
}try executa código arriscado. catch captura erros. finally executa sempre (limpeza). throw new Error() lança erros personalizados. Em async, use try/catch em vez de .catch().
Tratamento Global de Erros
// Erros não capturados
window.addEventListener("error", (e) => {
console.error("Erro global:", e.message);
console.error("Ficheiro:", e.filename);
console.error("Linha:", e.lineno);
// Enviar para serviço de logging
});
// Promises rejeitadas sem catch
window.addEventListener("unhandledrejection", (e) => {
console.error("Promise rejeitada:", e.reason);
e.preventDefault(); // não mostrar no console
});
// Error boundary em componentes (React-like)
class ErrorBoundary {
static capturar(fn, onError) {
try { return fn(); }
catch (e) { onError(e); return null; }
}
}window.onerror captura erros não tratados. unhandledrejection captura Promises sem .catch(). Útil para logging global e reportar erros a serviços como Sentry. Não substitui try/catch local.
Tipos de Erros
// TypeError: tipo errado
null.toString(); // TypeError
"str"(); // TypeError
// ReferenceError: variável não existe
console.log(x); // ReferenceError
// SyntaxError: código inválido
eval("if ("); // SyntaxError
// RangeError: valor fora do limite
new Array(-1); // RangeError
(1).toFixed(101); // RangeError
// URIError: URI inválida
decodeURIComponent("%"); // URIError
// Erro personalizado
class ValidationError extends Error {
constructor(campo, msg) {
super(msg);
this.name = "ValidationError";
this.campo = campo;
}
}
throw new ValidationError("email", "Inválido");Tipos nativos: TypeError (tipo errado), ReferenceError (não existe), SyntaxError (código inválido), RangeError (fora do limite). Crie classes com extends Error para erros custom.
AggregateError e Error Cause
// Error cause (ES2022)
try {
await fetch("/api");
} catch (e) {
throw new Error("Falha ao carregar dados", { cause: e });
}
// error.cause contém o erro original
// AggregateError: agrupar múltiplos erros
const erros = [
new Error("Campo nome obrigatório"),
new Error("Email inválido"),
new Error("Idade mínima: 18")
];
throw new AggregateError(erros, "Validação falhou");
// Promise.any lança AggregateError se todas falharem
try {
await Promise.any([p1, p2, p3]);
} catch (e) {
e.errors; // array de todos os erros
}Error cause ({ cause: e }) encadeia erros mantendo o original. AggregateError agrupa múltiplos erros num só. Promise.any() lança AggregateError quando todas as promises falham.
Error Boundary (Padrão)
// Wrapper genérico para operações arriscadas
function tentar(fn, fallback = null) {
try {
return { dados: fn(), erro: null };
} catch (e) {
return { dados: fallback, erro: e };
}
}
// Uso
const { dados, erro } = tentar(() => {
return JSON.parse(textoInvalido);
});
if (erro) {
console.error("Parse falhou:", erro.message);
}
// Async version
async function tentarAsync(fn, fallback = null) {
try {
return { dados: await fn(), erro: null };
} catch (e) {
return { dados: fallback, erro: e };
}
}
const { dados: user } = await tentarAsync(
() => fetch("/api/user").then(r => r.json())
);Padrão try/catch encapsulado: retorna { dados, erro } em vez de lançar. Evita try/catch repetido. Inspirado no padrão Result de linguagens funcionais. Versão async para Promises.
Debugging com DevTools
// debugger: pausa execução no DevTools
function calcular(x) {
debugger; // breakpoint manual
return x * 2;
}
// console.dir: ver estrutura do objeto
console.dir(document.body);
// Monitorar chamadas
const obj = { metodo() {} };
console.log(obj.metodo.toString());
// Performance
performance.now(); // timestamp preciso
performance.mark("inicio");
// ... código ...
performance.mark("fim");
performance.measure("op", "inicio", "fim");
// Ver medidas
performance.getEntriesByType("measure");
// Memory
// Chrome DevTools > Memory > Heap Snapshotdebugger; cria um breakpoint no código. performance.now() dá timestamps precisos. performance.mark()/measure() medem trechos. Use o DevTools para breakpoints condicionais e watch expressions.
Truques e Dicas
Desestruturação com Defaults
// Config com defaults
function criarServer({
host = "localhost",
port = 3000,
ssl = false,
db = { host: "localhost", port: 5432 }
} = {}) {
console.log(`${host}:${port}`);
}
criarServer(); // localhost:3000
criarServer({ port: 8080, ssl: true });
// Parâmetros opcionais com objeto
function buscar({ query = "", page = 1, limit = 10 } = {}) {
return `/api?q=${query}&p=${page}&l=${limit}`;
}
// Extrair com defaults
const { nome = "Anónimo", role = "user" } = getUser();Padrão de configuração: objeto com defaults + = {} para permitir chamar sem argumentos. Mais legível que parâmetros posicionais. Ideal para funções com muitas opções opcionais.
Encadeamento e Imutabilidade
// NÃO mutar — criar novo
const state = { items: [1, 2, 3], filtro: "todos" };
// Adicionar item
const novo = { ...state, items: [...state.items, 4] };
// Remover item
const sem2 = {
...state,
items: state.items.filter(i => i !== 2)
};
// Atualizar item
const atualizado = {
...state,
items: state.items.map(i =>
i === 2 ? { ...i, done: true } : i
)
};
// toSorted, toReversed, toSpliced (ES2023)
const ordenado = [3,1,2].toSorted(); // não muta!
const invertido = [1,2,3].toReversed();
const semPrimeiro = [1,2,3].toSpliced(0, 1);Imutabilidade: crie novos objetos/arrays em vez de mutar. spread + map/filter para transformações. ES2023: toSorted(), toReversed(), toSpliced() não mutam o original.
URLSearchParams e Query Strings
// Ler query string atual
const params = new URLSearchParams(window.location.search);
params.get("page"); // "2"
params.has("filtro"); // true/false
params.getAll("tag"); // ["js", "web"]
// Criar e modificar
const p = new URLSearchParams();
p.set("q", "javascript");
p.set("page", "1");
p.append("tag", "es6");
p.toString(); // "q=javascript&page=1&tag=es6"
// Atualizar URL sem reload
const url = new URL(window.location);
url.searchParams.set("page", "2");
history.pushState({}, "", url);
// Parse de URL completa
const u = new URL("https://api.com/dados?page=2&limit=10");
u.hostname; // "api.com"
u.pathname; // "/dados"
u.searchParams.get("page"); // "2"URLSearchParams manipula query strings facilmente. history.pushState() atualiza a URL sem recarregar. new URL() parseia URLs completas. Essencial para filtros, paginação e partilha de estado via URL.
Operações Úteis em Arrays
// Último elemento
const ultimo = arr.at(-1);
// Remover duplicados
const unico = [...new Set(arr)];
// Achatar
[[1,2],[3,4]].flat(); // [1,2,3,4]
[[1,[2,[3]]]].flat(Infinity); // [1,2,3]
// Agrupar (ES2024)
const items = [
{ tipo: "fruta", nome: "maçã" },
{ tipo: "legume", nome: "cenoura" },
{ tipo: "fruta", nome: "pera" }
];
const grupos = Object.groupBy(items, i => i.tipo);
// Chunk (dividir em grupos)
function chunk(arr, size) {
return Array.from({ length: Math.ceil(arr.length / size) },
(_, i) => arr.slice(i * size, (i + 1) * size));
}
chunk([1,2,3,4,5], 2); // [[1,2],[3,4],[5]].at(-1) acede ao último elemento. [...new Set()] remove duplicados. .flat(Infinity) achata totalmente. Object.groupBy() agrupa por chave. chunk() divide em grupos de tamanho fixo.
Sleep e Retry
// Sleep (pausa async)
const sleep = (ms) => new Promise(r => setTimeout(r, ms));
await sleep(1000); // pausa 1s
// Retry com tentativas
async function retry(fn, tentativas = 3) {
for (let i = 0; i < tentativas; i++) {
try { return await fn(); }
catch (e) {
if (i === tentativas - 1) throw e;
await sleep(1000 * (i + 1));
}
}
}
// Uso
const dados = await retry(() => fetch("/api").then(r => r.json()));sleep() pausa código async sem bloquear a thread. retry() repete operações que podem falhar com delay crescente (backoff). Essencial para chamadas de rede instáveis.
Debounce e Throttle
// Debounce: espera X ms após última chamada
function debounce(fn, delay = 300) {
let timer;
return (...args) => {
clearTimeout(timer);
timer = setTimeout(() => fn(...args), delay);
};
}
// Uso: pesquisa ao digitar
input.addEventListener("input", debounce((e) => {
buscar(e.target.value);
}, 500));
// Throttle: no máximo 1x a cada X ms
function throttle(fn, limit = 200) {
let ultimo = 0;
return (...args) => {
const agora = Date.now();
if (agora - ultimo >= limit) {
ultimo = agora;
fn(...args);
}
};
}
// Uso: scroll
window.addEventListener("scroll", throttle(() => {
verificarPosicao();
}, 100));Debounce espera X ms após a última chamada (pesquisa ao digitar). Throttle limita a 1 execução por X ms (scroll, resize). Ambos evitam excesso de chamadas a funções pesadas.
Memoize e Cache
// Memoize (cache de resultados)
function memoize(fn) {
const cache = new Map();
return (...args) => {
const key = JSON.stringify(args);
if (cache.has(key)) return cache.get(key);
const resultado = fn(...args);
cache.set(key, resultado);
return resultado;
};
}
// Uso: Fibonacci com cache
const fib = memoize((n) => n <= 1 ? n : fib(n-1) + fib(n-2));
fib(40); // rápido!
// Cache simples com Map
const cache = new Map();
async function getCached(url) {
if (cache.has(url)) return cache.get(url);
const res = await fetch(url).then(r => r.json());
cache.set(url, res);
return res;
}memoize() guarda resultados em cache — ideal para funções puras com cálculos pesados. Use Map como cache para requisições repetidas. Só funciona com funções determinísticas (mesmo input = mesmo output).
Deep Clone e Comparação
// Deep clone moderno
const original = { a: 1, b: { c: [1, 2] } };
const copia = structuredClone(original);
copia.b.c.push(3);
original.b.c; // [1, 2] (inalterado!)
// JSON (não copia funções, Date, undefined)
const copia2 = JSON.parse(JSON.stringify(original));
// Comparar objetos (shallow)
const a = { x: 1, y: 2 };
const b = { x: 1, y: 2 };
a === b; // false (referências diferentes)
// Shallow compare
const igual = JSON.stringify(a) === JSON.stringify(b);
// structuredClone suporta:
// Date, RegExp, Map, Set, ArrayBuffer, etc.structuredClone() faz deep clone nativo (suporta Date, Map, Set). JSON.parse(JSON.stringify()) é limitado (perde funções, Date vira string). Objetos comparam-se por referência, não valor.
Regex — Essencial
// Testar e extrair
const email = "ana@exemplo.com";
/^[\w.-]+@[\w.-]+\.\w+$/.test(email); // true
// Capturar grupos
const match = "2024-01-15".match(/(\d{4})-(\d{2})-(\d{2})/);
match[1]; // "2024"
match[2]; // "01"
match[3]; // "15"
// Named groups
const { groups } = "2024-01-15".match(
/(?<ano>\d{4})-(?<mes>\d{2})-(?<dia>\d{2})/
);
groups.ano; // "2024"
// Replace com regex
"10.50".replace(/\./g, ","); // "10,50"
"olá mundo".replace(/\b\w/g, c => c.toUpperCase());
// "Olá Mundo"
// Split
"a,b,,c".split(/,+/); // ["a","b","","c"].test() verifica se corresponde. .match() extrai grupos com (). (?<nome>) cria named groups. .replace() com /g substitui todas. \d = dígito, \w = palavra, + = 1 ou mais.