As funções construtoras em JavaScript são como as classes do Java, diferenciando apenas pela sintaxe. Em questão de funcionamento, tanto funções contrutoras no JavaScript quanto Classes no Java têm a mesma utilidade: servir de molde para a criação de objetos.

Para construir objetos, funções construtoras precisam ser instanciadas pelo operador new. O this dentro delas se referencia ao objeto criado a partir delas.

No exemplo abaixo, a função Carro é uma função construtora, e carro1 é um objeto criado a partir do “molde” dessa classe, usando o operador new:

function Carro(marca, modelo, ano){
    this.marca = marca
    this.modelo = modelo
    this.ano = ano
}

const carro1 = new Carro('Charger', 'RT', 1970)

console.log(carro1)

O JavaScript tem uma palavra reservada para classes?

Sim, existe um termo reservado para designar classes. No entanto, sua finalidade é ajudar a quem já sabe Java, para que fique mais familiarizado. Em se tratando de diferenças por herança, as classes no JavaScript não modificam em nada, e no fim elas se traduzem para funções.

Mas o que isso quer dizer? Isso significa que as classes no JavaScript são um tipo de função. Podemos constatar isso quando criamos uma classe ou uma função, e no final imprimir o Object.getPrototypeOf de cada uma delas.

Para classe, temos:

const classe = class{}

console.log(Object.getPrototypeOf(classe))

O retorno do console.log é [Function (anonymous)].

Para função, temos:

const funcao = function(){}

console.log(Object.getPrototypeOf(funcao))

E o console.log também imprime [Function (anonymous)].

Por isso é comum dizer que tudo em JavaScript é função! Por causa desses protótipos, qualquer função pode virar uma instância de construtor quando usado o operador new.

É preciso um return para ser considerado uma função construtora?

Normalmente, os construtores não têm um return. Isso acontece porque tudo o que lhes é informado é simplesmente passado ao this.

Por outro lado, havendo um return os comportamentos esperados são dois:

  • Se o return for chamado com um objeto, ele irá retornar no lugar do this.
  • Se o return for vazio ou seguido de um valor primitivo, ele será ignorado.

Nesse exmplo, o return está sendo utilizado dentro de um construtor seguido de um objeto:

function Aluno() {

    this.nome = "Miguel"
  
    return { nome: "Alexa" }  // esse será o objeto retornado!
  }
  
   console.log(new Aluno().nome)   // de fato, retornou "Alexa"

Já nesse caso, o return é vazio:

function Aluno() {

    this.nome = "Miguel"
  
    return // return vazio!
  }
  
  console.log(new Aluno().nome )// Acessa o this do construtor, que é Miguel

Qual a diferença entre retornar um objeto literal e um criado por função construtora?
Ao se criar objetos usando funções construtoras em JavaScript, estes seguirão o molde definido pela função, recebendo seus atributos e métodos.

Para criar objetos literais, é necessário um controle para garantir que os objetos tenham as mesmas propriedades. Uma solução é criá-los com uma função factory (“fábrica”), que garante o retorno de objetos literais com características explícitas. As funções factory são semelhantes às construtoras, mas sem o uso do new.