JavaScript

Como Usar Classes em JavaScript: Sintaxe, Herança e Encapsulamento em Produção

8 min de leitura

Como Usar Classes em JavaScript: Sintaxe, Herança e Encapsulamento em Produção

Fundamentos de Classes em JavaScript Classes em JavaScript são açúcar sintático construído sobre o modelo de protótipos, introduzidas na ES6 (2015). Diferentemente de linguagens clássicas, JavaScript usa protótipos internamente, mas as classes oferecem uma sintaxe familiar e mais legível para definir objetos e suas estruturas. Compreender essa abstração é essencial para trabalhar com código moderno e profissional. Uma classe é um molde para criar objetos com propriedades e métodos. Sua sintaxe é direta: declare com , defina o para inicializar propriedades e crie métodos para comportamentos. Veja um exemplo prático: ${this.marca} ${this.modelo} acelerando para ${this.velocidade} km/h ${this.marca} ${this.modelo} freado completamente Métodos e Propriedades Estáticas Métodos estáticos pertencem à classe, não às instâncias. Úteis para funcionalidades utilitárias que não dependem de dados de uma instância específica. Use a palavra-chave : Herança e Composição A herança permite que uma classe reutilize e estenda código de outra classe. Use para herdar e para acessar o construtor da classe pai. Este padrão é fundamental

<h2>Fundamentos de Classes em JavaScript</h2>

<p>Classes em JavaScript são açúcar sintático construído sobre o modelo de protótipos, introduzidas na ES6 (2015). Diferentemente de linguagens clássicas, JavaScript usa protótipos internamente, mas as classes oferecem uma sintaxe familiar e mais legível para definir objetos e suas estruturas. Compreender essa abstração é essencial para trabalhar com código moderno e profissional.</p>

<p>Uma classe é um molde para criar objetos com propriedades e métodos. Sua sintaxe é direta: declare com <code>class</code>, defina o <code>constructor</code> para inicializar propriedades e crie métodos para comportamentos. Veja um exemplo prático:</p>

<pre><code class="language-javascript">class Veiculo {

constructor(marca, modelo) {

this.marca = marca;

this.modelo = modelo;

this.velocidade = 0;

}

acelerar(incremento) {

this.velocidade += incremento;

console.log(${this.marca} ${this.modelo} acelerando para ${this.velocidade} km/h);

}

frear() {

this.velocidade = 0;

console.log(${this.marca} ${this.modelo} freado completamente);

}

}

const carro = new Veiculo(&#039;Toyota&#039;, &#039;Corolla&#039;);

carro.acelerar(60);

carro.frear();</code></pre>

<h3>Métodos e Propriedades Estáticas</h3>

<p>Métodos estáticos pertencem à classe, não às instâncias. Úteis para funcionalidades utilitárias que não dependem de dados de uma instância específica. Use a palavra-chave <code>static</code>:</p>

<pre><code class="language-javascript">class Calculadora {

static somar(a, b) {

return a + b;

}

static mediaAritmetica(numeros) {

const soma = numeros.reduce((acc, num) =&gt; acc + num, 0);

return soma / numeros.length;

}

}

console.log(Calculadora.somar(5, 3)); // 8

console.log(Calculadora.mediaAritmetica([10, 20, 30])); // 20</code></pre>

<h2>Herança e Composição</h2>

<p>A herança permite que uma classe reutilize e estenda código de outra classe. Use <code>extends</code> para herdar e <code>super()</code> para acessar o construtor da classe pai. Este padrão é fundamental em arquiteturas orientadas a objeto, mas use com moderação — frequentemente composição é mais flexível que herança profunda.</p>

<pre><code class="language-javascript">class Veiculo {

constructor(marca) {

this.marca = marca;

}

info() {

return Marca: ${this.marca};

}

}

class Carro extends Veiculo {

constructor(marca, portas) {

super(marca);

this.portas = portas;

}

info() {

return ${super.info()} | Portas: ${this.portas};

}

}

class Moto extends Veiculo {

constructor(marca, cilindrada) {

super(marca);

this.cilindrada = cilindrada;

}

info() {

return ${super.info()} | Cilindrada: ${this.cilindrada}cc;

}

}

const carro = new Carro(&#039;Honda&#039;, 4);

const moto = new Moto(&#039;Yamaha&#039;, 600);

console.log(carro.info()); // Marca: Honda | Portas: 4 console.log(moto.info()); // Marca: Yamaha | Cilindrada: 600cc</code></pre>

<h3>Evitando Hierarquias Profundas</h3>

<p>Em produção, evite heranças com mais de 2 ou 3 níveis. Prefira composição: injete comportamentos através de objetos passados ao construtor. Isso torna o código mais testável e flexível:</p>

<pre><code class="language-javascript">class MotorEletrico {

ligar() {

return &#039;Motor elétrico ligado silenciosamente&#039;;

}

}

class Bateria {

carga = 100;

descarregar() {

this.carga -= 10;

return Bateria em ${this.carga}%;

}

}

class VeiculoEletrico {

constructor(motor, bateria) {

this.motor = motor;

this.bateria = bateria;

}

ligarMotor() {

return this.motor.ligar();

}

usar() {

return this.bateria.descarregar();

}

}

const tesla = new VeiculoEletrico(new MotorEletrico(), new Bateria());

console.log(tesla.ligarMotor());

console.log(tesla.usar());</code></pre>

<h2>Encapsulamento: Privacidade e Controle</h2>

<p>O encapsulamento protege dados internos de acesso direto, expondo apenas o necessário através de uma interface pública. Em JavaScript moderno, propriedades privadas usam o prefixo <code>#</code>. Isso garante que apenas métodos internos à classe possam acessá-las, prevenindo modificações acidentais e facilitando refatoração segura em produção.</p>

<pre><code class="language-javascript">class ContaBancaria {

#saldo = 0;

#historico = [];

constructor(titular, saldoInicial = 0) {

this.titular = titular;

this.#saldo = saldoInicial;

this.#historico.push({ operacao: &#039;Abertura&#039;, valor: saldoInicial, data: new Date() });

}

depositar(valor) {

if (valor &lt;= 0) {

throw new Error(&#039;Valor deve ser positivo&#039;);

}

this.#saldo += valor;

this.#historico.push({ operacao: &#039;Depósito&#039;, valor, data: new Date() });

return Depósito de R$${valor} realizado. Saldo: R$${this.#saldo};

}

sacar(valor) {

if (valor &gt; this.#saldo) {

throw new Error(&#039;Saldo insuficiente&#039;);

}

this.#saldo -= valor;

this.#historico.push({ operacao: &#039;Saque&#039;, valor, data: new Date() });

return Saque de R$${valor} realizado. Saldo: R$${this.#saldo};

}

obterSaldo() {

return this.#saldo;

}

obterHistorico() {

return [...this.#historico];

}

}

const conta = new ContaBancaria(&#039;João&#039;, 1000);

console.log(conta.depositar(500));

console.log(conta.sacar(200));

console.log(conta.obterSaldo());

// conta.#saldo = -9999; // Erro: propriedade privada é inacessível</code></pre>

<h3>Getters e Setters</h3>

<p>Getters e setters permitem validação e lógica customizada ao acessar propriedades, mantendo a sintaxe de propriedades simples. Essencial para classes em produção que precisam de regras de negócio:</p>

<pre><code class="language-javascript">class Usuario {

#email;

#idade;

constructor(nome, email, idade) {

this.nome = nome;

this.email = email;

this.idade = idade;

}

get email() {

return this.#email;

}

set email(novoEmail) {

if (!novoEmail.includes(&#039;@&#039;)) {

throw new Error(&#039;Email inválido&#039;);

}

this.#email = novoEmail;

}

get idade() {

return this.#idade;

}

set idade(novaIdade) {

if (novaIdade &lt; 0 || novaIdade &gt; 150) {

throw new Error(&#039;Idade inválida&#039;);

}

this.#idade = novaIdade;

}

}

const usuario = new Usuario(&#039;Maria&#039;, &#039;maria@email.com&#039;, 28);

console.log(usuario.email);

usuario.idade = 29;

console.log(usuario.idade);

// usuario.email = &#039;invalido&#039;; // Erro: Email inválido</code></pre>

<h2>Boas Práticas em Produção</h2>

<p>Em ambientes reais, siga estas diretrizes: (1) <strong>Use encapsulamento por padrão</strong> — propriedades privadas protegem sua arquitetura; (2) <strong>Prefira composição a herança profunda</strong> — é mais simples de entender e testar; (3) <strong>Valide dados nos setters e construtores</strong> — evita estados inválidos; (4) <strong>Documente com JSDoc</strong> — facilita manutenção futura.</p>

<pre><code class="language-javascript">/**

  • Classe que representa um Produto no sistema de e-commerce
  • @class Produto
  • @param {string} nome - Nome do produto
  • @param {number} preco - Preço em reais
  • @param {number} estoque - Quantidade em estoque

*/

class Produto {

#preco;

#estoque;

constructor(nome, preco, estoque) {

this.nome = nome;

this.preco = preco;

this.estoque = estoque;

}

get preco() {

return this.#preco;

}

set preco(valor) {

if (valor &lt;= 0) throw new Error(&#039;Preço deve ser positivo&#039;);

this.#preco = valor;

}

/**

  • Reduz estoque após venda
  • @param {number} quantidade
  • @returns {boolean} Sucesso da operação

*/

vender(quantidade) {

if (quantidade &gt; this.#estoque) return false;

this.#estoque -= quantidade;

return true;

}

obterEstoque() {

return this.#estoque;

}

}

const produto = new Produto(&#039;Notebook&#039;, 3000, 5);

produto.vender(2);

console.log(produto.obterEstoque()); // 3</code></pre>

<h2>Conclusão</h2>

<p>Classes em JavaScript oferecem uma abordagem profissional e estruturada para organizar código. O domínio de <strong>herança com <code>extends</code> e <code>super</code></strong>, <strong>encapsulamento com propriedades privadas</strong> e <strong>getters/setters com validação</strong> é indispensável em projetos reais. Lembre-se: prefira composição quando possível, sempre valide dados e documente sua código — essas práticas garantem manutenibilidade a longo prazo.</p>

<h2>Referências</h2>

<ul>

<li><a href="https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/Classes" target="_blank" rel="noopener noreferrer">MDN Web Docs - Classes</a></li>

<li><a href="https://tc39.es/ecma262/#sec-class-definitions" target="_blank" rel="noopener noreferrer">ECMAScript 2022 Specification - Class</a></li>

<li><a href="https://github.com/getify/You-Dont-Know-JS" target="_blank" rel="noopener noreferrer">You Don&#039;t Know JS Yet: Objects &amp; Classes</a></li>

<li><a href="https://javascript.info/classes" target="_blank" rel="noopener noreferrer">JavaScript.info - Classes</a></li>

<li><a href="https://www.typescriptlang.org/docs/handbook/2/classes.html" target="_blank" rel="noopener noreferrer">TypeScript Handbook - Classes</a></li>

</ul>

Comentários

Mais em JavaScript

Dominando Currying e Partial Application em JavaScript em Projetos Reais
Dominando Currying e Partial Application em JavaScript em Projetos Reais

Currying: A Arte de Transformar Funções Currying é uma técnica que transforma...

Introdução ao JavaScript: História, Engines e Como o Navegador Executa JS: Do Básico ao Avançado
Introdução ao JavaScript: História, Engines e Como o Navegador Executa JS: Do Básico ao Avançado

História e Evolução do JavaScript JavaScript nasceu em 1995, criado por Brend...

Guia Completo de Testes End-to-End em JavaScript com Playwright e Cypress
Guia Completo de Testes End-to-End em JavaScript com Playwright e Cypress

Introdução aos Testes End-to-End Testes end-to-end (E2E) verificam sua aplica...