O que é JavaScript?
JavaScript é uma linguagem de programação que roda dentro de um ambiente hospedeiro e permite que você controle o que acontece em uma página. O HTML fornece a estrutura, o CSS fornece a apresentação e o JavaScript fornece o comportamento. Quando um menu abre, um formulário é validado, uma página carrega novos dados sem atualizar ou um jogo responde ao seu teclado, é o JavaScript que está fazendo o trabalho.
É uma linguagem de alto nível, com tipagem dinâmica e multiparadigma. Esse termo complexo significa simplesmente que: você não gerencia a memória manualmente, não declara tipos antecipadamente e pode escrever em um estilo orientado a objetos, funcional ou imperativo, conforme a demanda do problema.
A linguagem foi criada em 1995 para uma única função — tornar as páginas web um pouco interativas — e ela extrapolou completamente esse limite. Hoje, a mesma sintaxe roda servidores, apps móveis, ferramentas de linha de comando e aplicações desktop. Aprendê-la é um dos investimentos de maior retorno que você pode fazer no desenvolvimento web.
Onde o JavaScript é executado
JavaScript é a linguagem. Um runtime é o ambiente que a executa. O runtime mais familiar é o navegador, mas ele está longe de ser o único.
- Navegadores trazem um motor JavaScript (V8 no Chrome, SpiderMonkey no Firefox, JavaScriptCore no Safari) além de APIs de host como o DOM,
fetch, timers e storage. - Node.js, Deno e Bun executam JavaScript no servidor com APIs para arquivos, redes e processos.
- Runtimes embarcados executam JavaScript em apps mobile, apps desktop, bancos de dados e até microcontroladores.
A linguagem em si é padronizada como ECMAScript. O DOM, fetch e console não fazem parte da linguagem — eles são APIs que o runtime fornece. Manter essa distinção em mente explica por que o mesmo código funciona em um ambiente e não em outro.
Variáveis: let, const e var
Uma variável é uma referência nomeada a um valor. O JavaScript moderno possui três maneiras de criar uma, mas você só precisará de duas.
// app.js
const name = "Ada"; // cannot be reassigned
let score = 0; // can be reassigned
score = score + 10;
// var is the legacy form — avoid it in new code
var old = true;
Use const por padrão. Isso não torna o valor imutável — você ainda pode alterar o conteúdo de um objeto ou array const — apenas impede que o nome seja vinculado a um valor diferente. Use let quando um valor realmente mudar, como em um contador ou acumulador. Utilize var apenas ao ler códigos antigos.
Tipos de dados
O JavaScript possui um pequeno conjunto de tipos primitivos além de objetos.
| Tipo | Exemplo | Notas |
| — | — — | — |
| string | "hello" | Texto, aspas simples, duplas ou crases |
| number | 42, 3.14 | Um único tipo numérico para inteiros e floats |
| bigint | 9007199254740993n | Inteiros arbitrariamente grandes |
| boolean | true, false | Valores lógicos |
| undefined | undefined | Um valor declarado, mas não atribuído |
| null | null | Uma ausência intencional de valor |
| symbol | Symbol("id") | Identificadores únicos |
| object | { name: "Ada" } | Coleções, funções, arrays — todo o restante |
O operador typeof informa com o que você está trabalhando. Fique atento a duas peculiaridades famosas: typeof null é "object" (um bug histórico mantido por compatibilidade) e typeof uma função é "function", embora funções sejam objetos.
Funções
Funções são blocos de lógica reutilizáveis e, em JavaScript, elas são valores. Você pode armazená-las em variáveis, passá-las como argumentos e retorná-las de outras funções.
// greet.js
function greet(name) {
return `Hello, ${name}!`;
}
const add = (a, b) => a + b;
const shout = (text) => text.toUpperCase();
A forma de declaração function sofre hoisting, portanto pode ser chamada antes de aparecer no código. Arrow functions (=>) são mais curtas, não possuem seu próprio this e são ideais para callbacks. Quando uma função contém apenas uma única expressão, o corpo e o return podem ser omitidos.
Funções também podem ter parâmetros padrão e aceitar um número variável de argumentos através da sintaxe rest:
// math.js
function sum(...numbers) {
return numbers.reduce((total, n) => total + n, 0);
}
function greet(name = "friend") {
return `Hi, ${name}`;
}
sum(1, 2, 3); // 6
Objetos e arrays
Objetos armazenam valores nomeados; arrays armazenam valores ordenados. Juntos, eles modelam quase todos os tipos de dados que você irá manipular.
// data.js
const user = {
name: "Ada",
age: 36,
admin: true,
};
const skills = ["HTML", "CSS", "JavaScript"];
user.name; // "Ada"
skills.length; // 3
skills[0]; // "HTML"
Você pode fazer a desestruturação de ambos para extrair valores de forma limpa, e utilizar o spread para criar cópias:
// destructure.js
const { name, age } = user;
const [first, ...rest] = skills;
const updated = { ...user, age: 37 };
const moreSkills = [...skills, "TypeScript"];
Objetos e arrays são tipos de referência. Atribuir um deles a outra variável copia a referência, e não o conteúdo; portanto, mutar através de qualquer um dos nomes altera o mesmo valor subjacente. O spread cria uma cópia rasa (shallow copy) para quando você precisar de independência.
Fluxo de controle
Condicionais e loops direcionam o fluxo do seu programa.
// logic.js
if (score >= 90) {
grade = "A";
} else if (score >= 80) {
grade = "B";
} else {
grade = "C";
}
for (const skill of skills) {
console.log(skill);
}
Prefira for...of para arrays e for...in apenas para enumerar chaves de objetos. O operador ternário condition ? a : b é uma expressão compacta para quando você precisa de um valor em vez de um bloco com efeitos colaterais. O operador de coalescência nula ?? e o encadeamento opcional (optional chaining) ?. tornam o código defensivo mais legível:
// safe.js
const city = user.address?.city ?? "Unknown";
Escopo e closures
Escopo é onde uma variável está visível. Um bloco { } cria um escopo para let e const. Uma função cria um escopo para tudo o que estiver dentro dela. Closures são a consequência disso: uma função interna mantém o acesso às variáveis da função externa, mesmo depois que essa função já retornou.
// counter.js
function createCounter() {
let count = 0;
return function () {
count += 1;
return count;
};
}
const next = createCounter();
next(); // 1
next(); // 2
A função retornada “fecha” (closes over) count, mantendo-a viva e privada. Closures alimentam event handlers, memoisation, currying e padrões de módulo. Elas são um dos conceitos mais importantes da linguagem e, assim que você as compreende, muita coisa no JavaScript começa a fazer sentido.
O event loop, uma primeira olhada
O JavaScript executa seu código em uma única thread — ele só consegue fazer uma coisa por vez. No entanto, ele nunca trava enquanto espera por uma requisição de rede. O segredo é o event loop.
O código síncrono é executado imediatamente na call stack. Quando você agenda algo assíncrono, como um timer ou um fetch, o runtime delega essa tarefa e continua a execução. Quando a tarefa termina, seu callback é colocado em uma fila. O event loop processa o trabalho enfileirado apenas quando a stack está vazia.
// loop.js
console.log("1");
setTimeout(() => console.log("2"), 0);
console.log("3");
// Output: 1, 3, 2
Mesmo com um atraso de zero milissegundos, o callback espera até que o código síncrono atual termine. Essa ordenação é a base das promises e de async/await, abordados detalhadamente no guia de Async JavaScript.
Como adicionar JavaScript a uma página
Você anexa JavaScript ao HTML com um elemento <script>. Coloque-o ao final do body ou use o atributo defer para que o HTML seja processado antes da execução do seu código.
<!-- index.html -->
<body>
<h1>Hello</h1>
<script src="app.js" defer></script>
</body>
Scripts inline também funcionam, mas arquivos externos são cacheáveis, reutilizáveis e mais fáceis de depurar. Use type="module" para carregar ES modules com import e export.
Erros comuns
- Usar
vare se surpreender com o hoisting ou com o escopo de função. - Comparar com
==e causar uma coerção de tipo inesperada. Use===. - Mutar um objeto ou array assumindo que uma cópia foi criada.
- Esquecer que o
thisdepende de como a função é chamada, e não de onde ela foi definida. - Tratar
nulleundefinedcomo intercambiáveis sem um motivo. - Recorrer a um framework antes de entender funções e objetos puros.
Melhores práticas
- Prefira
const, depoislet, e evitevar. - Sempre use
===e!==, a menos que você queira especificamente a coerção. - Mantenha as funções pequenas e focadas em apenas uma tarefa.
- Nomeie as coisas pelo que elas significam, não pelo que elas são.
- Use optional chaining e nullish coalescing para acessos seguros.
- Aprenda a linguagem antes do framework. Os fundamentos duram mais que as ferramentas.
O que aprender a seguir
Agora você já tem o modelo mental: valores, variáveis, funções, objetos, escopo e o event loop. A partir daqui, os próximos passos naturais são o DOM para interagir com páginas, recursos do ES6+ para a sintaxe moderna e JavaScript assíncrono para promises e async/await. Escolha um, construa algo pequeno e deixe a prática acumular.