Classes e Módulos em JavaScript
Conforme os projetos crescem, você precisa de mais do que funções e variáveis espalhadas — precisa de estrutura organizada de código. Classes fornecem padrões orientados a objetos, e Módulos fornecem isolamento de código no nível de arquivo. Juntos, formam a base de projetos JS modernos.
Sintaxe de Classe
Uma Classe é um modelo para criar objetos — açúcar sintático sobre funções construtoras.
<script>
class NomeClasse {
constructor(params) {
this.propriedade = params;
}
metodo() {
// ...
}
}
</script>
Exemplo: Criando uma Classe Aluno
<div id="output" style="padding: 10px; border: 1px solid #ccc;"></div>
<script>
const output = document.getElementById('output');
class Aluno {
constructor(nome, idade, serie) {
this.nome = nome;
this.idade = idade;
this.serie = serie;
}
apresentar() {
return 'Meu nome é ' + this.nome + ', tenho ' + this.idade + ' anos, estou no ' + this.serie + '.';
}
estudar(materia) {
return this.nome + ' está estudando ' + materia + '.';
}
}
const a1 = new Aluno('Alice', 12, '6º ano');
const a2 = new Aluno('Bob', 11, '5º ano');
output.textContent = a1.apresentar() + '\n' + a2.apresentar() + '\n' + a1.estudar('Matemática');
</script>
class é essencialmente açúcar sintático sobre funções construtoras + protótipos. new Aluno() funciona igual ao antigo new function Aluno(), mas a sintaxe é mais limpa e intuitiva.
Propriedades e Métodos
Propriedades e Métodos de Instância
Propriedades e métodos definidos com this.xxx dentro do constructor pertencem à instância — cada objeto recebe sua própria cópia.
Métodos Estáticos
Métodos definidos com a palavra-chave static pertencem à classe em si, não às instâncias. Chame-os via NomeClasse.metodo().
Getters e Setters
Use as palavras-chave get e set para definir "propriedades virtuais" — funções que executam automaticamente na leitura/escrita.
<div id="output" style="white-space: pre; font-family: monospace; padding: 10px; border: 1px solid #ccc;"></div>
<script>
const output = document.getElementById('output');
class Pessoa {
constructor(primeiroNome, sobrenome) {
this.primeiroNome = primeiroNome;
this.sobrenome = sobrenome;
}
get nomeCompleto() {
return this.primeiroNome + ' ' + this.sobrenome;
}
set nomeCompleto(valor) {
const partes = valor.split(' ');
this.primeiroNome = partes[0];
this.sobrenome = partes[1];
}
}
const p = new Pessoa('João', 'Silva');
output.textContent = 'nomeCompleto: ' + p.nomeCompleto + '\n';
p.nomeCompleto = 'Maria Santos';
output.textContent += 'Após alteração: ' + p.nomeCompleto;
</script>
Exemplo: Métodos Estáticos e Getters/Setters
<div id="output" style="white-space: pre; font-family: monospace; padding: 10px; border: 1px solid #ccc;"></div>
<script>
const output = document.getElementById('output');
class Circulo {
static contagem = 0;
constructor(raio) {
this.raio = raio;
Circulo.contagem++;
}
get area() {
return Math.PI * this.raio * this.raio;
}
get diametro() {
return this.raio * 2;
}
set diametro(valor) {
this.raio = valor / 2;
}
static criarUnidade() {
return new Circulo(1);
}
}
const c1 = new Circulo(5);
const c2 = new Circulo(10);
const c3 = Circulo.criarUnidade();
output.textContent = 'Círculo com raio 5:\n';
output.textContent += ' Área: ' + c1.area.toFixed(2) + '\n';
output.textContent += ' Diâmetro: ' + c1.diametro + '\n';
output.textContent += ' Definir diâmetro como 20:\n';
c1.diametro = 20;
output.textContent += ' Novo raio: ' + c1.raio + '\n\n';
output.textContent += 'Total de círculos criados: ' + Circulo.contagem + '\n';
output.textContent += 'Raio do círculo unitário: ' + c3.raio;
</script>
Herança
extends permite que uma classe filha herde propriedades e métodos de uma classe pai. super chama o construtor ou métodos do pai.
Exemplo: Demonstração de Herança
<div id="output" style="white-space: pre; font-family: monospace; padding: 10px; border: 1px solid #ccc;"></div>
<script>
const output = document.getElementById('output');
class Animal {
constructor(nome, som) {
this.nome = nome;
this.som = som;
}
falar() {
return this.nome + ' diz: ' + this.som;
}
}
class Cachorro extends Animal {
constructor(nome, raca) {
super(nome, 'Au Au');
this.raca = raca;
}
buscar(item) {
return this.nome + ' buscou o ' + item;
}
}
class Gato extends Animal {
constructor(nome, interno) {
super(nome, 'Miau');
this.interno = interno;
}
ronronar() {
return this.nome + ' está ronronando...';
}
}
const cachorro = new Cachorro('Rex', 'Shiba Inu');
const gato = new Gato('Miau', true);
output.textContent = cachorro.falar() + '\n';
output.textContent += cachorro.buscar('frisbee') + '\n';
output.textContent += gato.falar() + '\n';
output.textContent += gato.ronronar();
</script>
constructor de uma classe filha, você deve chamar super() antes de usar this — porque até o pai ser inicializado, o this do filho não existe. Esta é a regra mais fácil de esquecer ao aprender herança.
Módulos ES
Módulos são a unidade de organização de código do JS. Um módulo = um arquivo. Variáveis dentro de um módulo são privadas por padrão — apenas itens explicitamente exportados são acessíveis externamente.
Exportações/Importações Nomeadas
<script>
// math.js
export const PI = 3.14;
export function somar(a, b) { return a + b; }
// app.js
import { PI, somar } from './math.js';
</script>
Exportações/Importações Padrão
<script>
// logger.js
export default function log(msg) { console.log(msg); }
// app.js
import log from './logger.js';
</script>
Usando Módulos em HTML
Simplesmente adicione type="module" à tag script.
<script type="module">
import { somar } from './math.js';
console.log(somar(1, 2));
</script>
Exemplo: Simulação de Módulo em Arquivo Único (Módulo Inline)
Em projetos reais, módulos devem ser divididos em arquivos separados. Aqui simulamos dentro de um único arquivo HTML usando type="module".
<div id="output" style="padding: 10px; border: 1px solid #ccc;"></div>
<script type="module">
const output = document.getElementById('output');
const calculadora = {
somar(a, b) { return a + b; },
subtrair(a, b) { return a - b; },
multiplicar(a, b) { return a * b; },
dividir(a, b) { return b !== 0 ? a / b : 'Não é possível dividir por zero'; }
};
const formatador = {
moeda(valor) { return 'R$' + valor.toFixed(2); },
porcentagem(valor) { return (valor * 100).toFixed(1) + '%'; }
};
const r1 = calculadora.somar(10, 20);
const r2 = calculadora.multiplicar(5, 4);
const r3 = calculadora.dividir(10, 3);
output.textContent = '10 + 20 = ' + r1 + '\n';
output.textContent += '5 × 4 = ' + r2 + '\n';
output.textContent += '10 ÷ 3 = ' + formatador.moeda(r3) + '\n';
output.textContent += '0.85 → ' + formatador.porcentagem(0.85);
// Em um projeto real você dividiria assim:
// calculadora.js → export { calculadora }
// formatador.js → export { formatador }
// main.js → import { calculadora } from './calculadora.js'
// import { formatador } from './formatador.js'
</script>
📖 Resumo
classé açúcar sintático sobre construtores;constructoré o inicializador, e métodos são definidos no protótipo- Métodos
staticpertencem à classe, não às instâncias — ideais para métodos utilitários e de fábrica get/setdefinem propriedades virtuais que interceptam leituras/escritas para validação ou computaçãoextendshabilita herança; oconstructorfilho deve chamarsuper()primeiro- Módulos ES usam
export/importpara isolamento e reuso de código;type="module"os habilita em HTML - Módulos organizam código por funcionalidade, permitem carregamento preguiçoso e evitam poluição do namespace global
❓ Perguntas Frequentes
P: Qual a diferença real entre Classe e função construtora? R: Nenhuma diferença fundamental — Classe é açúcar sintático. Mas Classes têm algumas características: devem ser chamadas com
new(não podem rodar como funções comuns), métodos são não enumeráveis, e o modo estrito é ativado por padrão. A sintaxe é mais limpa, então Classes são recomendadas.
P: Qual a diferença entre
importerequire? R:importé sintaxe de módulo ES — analisada estaticamente em tempo de compilação.requireé CommonJS (Node.js) — carregada dinamicamente em tempo de execução. Navegadores suportam nativamente apenas módulos ES.importdeve estar no nível superior;requirepode estar em qualquer lugar.
P: É possível misturar exportações padrão e nomeadas? R: Sim. Um módulo pode ter uma exportação padrão e múltiplas exportações nomeadas:
export default App; export const utils = {};. Importe com:import App, { utils } from './modulo.js'.
📝 Atividades
- Básico: Crie uma classe
Retangulocom propriedadeslarguraealtura, além dos métodosobterArea()eobterPerimetro(). - Intermediário: Adicione um getter
get area()e setterset area(valor)aoRetangulo(definir área ajusta largura/altura proporcionalmente). Depois crie uma subclasseQuadradoque estendaRetangulo. - Desafio: Projete uma classe
GerenciadorEventoscom métodoson(evento, callback),off(evento, callback)eemit(evento, dados)para simular um sistema simples de eventos (dica: use um objeto mapeando eventos para arrays de callbacks).



