Menu

Classes em JavaScript: construtor, métodos e new

Entenda como as classes em JavaScript funcionam na prática: construtor, métodos, campos de instância, getters e setters, e o modelo mental por trás do class.

Uma classe é um molde para objetos

Uma classe descreve o formato e o comportamento de um tipo de objeto. Você define o molde uma única vez e, a partir dele, cria quantas instâncias precisar. Cada instância guarda seus próprios dados, mas compartilha os mesmos métodos.

A estrutura básica fica assim:

index.js
Output
Click Run to see the output here.

class User { ... } define o molde. new User(...) cria uma instância. Cada instância tem seu próprio name e email, mas ambas compartilham o mesmo método greet definido na classe.

Duas instâncias, dois conjuntos de dados, um único conjunto de métodos. A ideia é basicamente essa.

O constructor prepara cada instância

O constructor é um método especial que roda exatamente uma vez por instância, no momento em que new a cria. A função dele é inicializar o objeto recém-criado — normalmente copiando os argumentos para o this:

index.js
Output
Click Run to see the output here.

this dentro do construtor se refere à nova instância que está sendo criada naquele momento. Ao fazer this.x = x, você está colocando x naquele objeto específico. Cada chamada new Point(...) recebe seu próprio this e, portanto, seu próprio x e y.

Se você não escrever um construtor, o JavaScript cria um vazio automaticamente pra você. Só vale a pena escrever um quando existe de fato alguma inicialização a ser feita.

O new é o que faz tudo funcionar

Chamar uma classe sem new lança um erro:

const p = Point(3, 4);
// TypeError: Class constructor Point cannot be invoked without 'new'

Isso é proposital. O new faz quatro coisas, nessa ordem:

  1. Cria um objeto vazio novinho.
  2. Liga esse objeto ao prototype da classe (onde ficam os métodos).
  3. Executa o constructor com o this apontando para o novo objeto.
  4. Retorna o objeto.

Sem o new, nada disso acontece. A classe obriga você a seguir essa regra, então não tem como esquecer por descuido — uma baita melhoria em relação à época anterior ao class, quando esquecer o new corrompia o objeto global silenciosamente.

Métodos são compartilhados, campos de instância não

Os métodos declarados dentro do corpo da classe vivem no prototype — existe uma única cópia, compartilhada entre todas as instâncias. Já os campos de instância (tudo que você atribui ao this) são individuais: cada instância tem os seus.

index.js
Output
Click Run to see the output here.

As duas instâncias têm o próprio count, então incrementar uma não mexe na outra. Mas a.increment e b.increment são, literalmente, a mesma função — ela fica armazenada uma única vez no prototype e é consultada sempre que você chama em alguma instância. É por isso que classes escalam barato: mil instâncias não geram mil cópias de cada método.

Campos de instância em JavaScript

Dá pra declarar os campos de instância logo no topo do corpo da classe, fora do construtor:

index.js
Output
Click Run to see the output here.

As declarações de campos rodam antes do corpo do construtor, como se estivessem escritas no topo do constructor. Isso é útil quando o valor inicial não depende dos argumentos do construtor — fica mais limpo do que poluir o construtor com this.count = 0; this.step = 1;.

Quando os valores realmente dependem de argumentos, mantenha a atribuição dentro do construtor, onde esses argumentos estão acessíveis.

Getters e setters em JavaScript

Um getter ou setter tem cara de método, mas se comporta como acesso a propriedade. Você lê ou atribui sem parênteses, e o método é executado por baixo dos panos:

index.js
Output
Click Run to see the output here.

Observe como é feita a chamada: t.fahrenheit (sem parênteses) aciona o getter, enquanto t.fahrenheit = 100 dispara o setter. Visto de fora, fahrenheit parece uma propriedade comum, mas na verdade é calculada na hora a partir de celsius.

Getters são ótimos para valores derivados. Já os setters caem bem quando você quer validar ou normalizar um valor no momento da atribuição. Só não abuse — se um getter for custoso, quem estiver lendo seu código vai estranhar que um simples "acesso a propriedade" esteja fazendo tanto trabalho por baixo dos panos.

Métodos de classe, nomes computados e o this

Dentro de uma classe, os métodos usam uma sintaxe enxuta — sem a palavra-chave function e sem : separando o nome do corpo:

index.js
Output
Click Run to see the output here.

Devolver this em add é o que habilita o encadeamento de métodos — cada chamada retorna a própria instância, e o próximo método pode rodar em cima dela.

Um detalhe que pega muita gente: os métodos não ficam automaticamente vinculados à instância. Se você extrair um método e chamá-lo de forma isolada, o this se perde:

index.js
Output
Click Run to see the output here.

Chamar g.hello() funciona porque o . fornece o this. Já chamar fn() sozinho, não. Se você precisa de um método destacado e já com this amarrado (algo comum em event handlers), faça o bind no construtor ou use um campo de classe com arrow function: hello = () => \Oi, ${this.name}`;`.

Um exemplo prático de classe em JavaScript

Juntando as peças — campos, construtor, métodos e um getter:

index.js
Output
Click Run to see the output here.

Dá pra entender tudo batendo o olho: a classe deixa claro o que é uma BankAccount e o que ela sabe fazer.

No fundo, classes em JavaScript são funções

Uma coisa que vale a pena fixar: class é basicamente açúcar sintático. Por baixo dos panos, uma classe é uma função — mais precisamente, uma função construtora — e seus métodos ficam em NomeDaClasse.prototype:

index.js
Output
Click Run to see the output here.

typeof User devolve "function". O greet fica em User.prototype. As instâncias encontram o greet percorrendo a cadeia de protótipos — o mesmo mecanismo que existe na linguagem desde o primeiro dia. As classes só oferecem uma sintaxe mais limpa para montar tudo isso.

Esse modelo mental compensa lá na frente: herança, instanceof e depurar cadeias de protótipos passam a fazer muito mais sentido quando você lembra que uma classe em JavaScript é, no fundo, uma função com métodos pendurados no seu prototype.

A seguir: herança

Até aqui, cada classe vive por conta própria. Mas, na prática, quase todo projeto real constrói hierarquias de classes — um Dog que é um tipo de Animal, um AdminUser que é um tipo de User. É aí que entram as palavras-chave extends e super, que é justamente o nosso próximo assunto.

Perguntas frequentes

Como criar uma classe em JavaScript?

Use a palavra-chave class seguida do nome e um bloco com o método constructor e os demais métodos. Para criar uma instância, basta chamar new NomeDaClasse(...). Exemplo: class User { constructor(name) { this.name = name; } } e depois new User('Ada').

Para que serve o constructor em uma classe JavaScript?

O constructor é executado uma única vez, quando você chama new NomeDaClasse(...). A função dele é configurar a nova instância — normalmente atribuindo os argumentos a this como propriedades. Se você não definir um, o JavaScript cria um constructor vazio por padrão.

Qual a diferença entre class e function em JavaScript?

Por baixo dos panos, uma classe é uma função — mais especificamente, uma função construtora com os métodos anexados ao prototype. O class é, em boa parte, açúcar sintático, mas ele obriga o uso de new, deixa o extends muito mais limpo e torna os métodos não-enumeráveis. Em código novo, prefira class em vez de escrever funções construtoras na mão.

Aprenda a programar com o Coddy

COMEÇAR