Gabriel
Gabriel20/08/2022 01:24
Compartilhe

Entendendo o Operador “New” (JavaScript)

  • #JavaScript

Fala, pessoal! Meu nome é Gabriel e hoje eu vim aqui falar um pouquinho sobre o Operador New no JavaScript, porque particularmente pra mim foi bemmm difícil de entrar na cabeça… Espero que gostem 🙂

Pra quem quiser me seguir, meu Instagram é @grbrielcosta

(eu não revisei o artigo, então, pode ser que tenha alguns erros de pt… escrevi enquanto estudava e estou postando aqui!! mas apesar disso, acredito que dá pra entender de boassss)

///////////////////////////

Muitos desenvolvedores, inclusive os avançados, não procuram entender afundo sobre o operador New e acabam sem entender as grandes diferenças que existem entre se invocar uma função utilizando o New e invocar sem utilizá-lo…

Hoje, neste artigo, vou te mostrar e te exemplificar da forma mais prolixa possível como esse operador funciona no JavaScript!

A primeira coisa que precisamos entender é que uma função no JavaScript pode ser invocada de várias maneiras diferentes. Neste artigo, falaremos da invocação como função e na invocação como construtor…

Pra começar, vamos ao nosso editor de código (VSCode no meu caso) e vamos escrever as seguintes sentenças de código:

function Pessoa() {

}

var joao = Pessoa()
var maria = new Pessoa()

Nesse código, você pode perceber que na primeira linha eu criei uma f unção chamada ‘Pessoa’ e a deixei vazia. Logo depois da função, criei duas variáveis: uma armazenando a função ‘Pessoa’ e na outra armazenando a função ‘Pessoa’, porém, com o operador New na frente.

Quando colocamos o operador New na frente, estamos dizendo para o console que a função que está sendo chamada é uma Função Construtora.

Agora, vamos logar essas duas variáveis no console…

console.log(joao, maria)

Logo de cara, já conseguimos notar uma diferença. O console me retornou resultados diferentes. A primeira variável, no caso ‘joao’, me retornou o valor undefined. Já a segunda variável, ‘maria’, me retornou um Objeto chamado ‘Pessoa’.

primeira variavel --> undefined // segunda variável --> Pessoa {}

A primeira grande diferença é que, quando você utiliza o operador New, internamente, o JavaScript vai criar um novo objeto, como no exemplo abaixo…

E como você também não definiu um valor de retorno, o JavaScript retorna esse mesmo objeto que ele criou…

function Pessoa() {

// var obj = {}
// return obj

}

A outra grande diferença de se utilizar o operador New se diz respeito ao Contexto da função

Ou seja, ao parâmetro implícito “THIS

Quando chamamos uma função como função, o “THIS” será uma referência ao objeto global.

No caso do navegador, é o Window, e no caso do node é o Global.

function Pessoa() {

// var obj = { }

// this = window
// this = global

// return obj
}

Mas, quando você chama a função como Construtora, ou seja, utilizando o operador New, o “THIS” será uma referência ao próprio objeto criado pelo operador New!

function Pessoa() {

// var obj = { }

// this = obj

// return obj
}

Com isso em mente, você pode perceber que você pode trabalhar com o this da mesma maneira como você trabalha com qualquer outro objeto…

Vamos começar a atribuir propriedades e métodos igual fazemos com qualquer outro tipo de objeto… Veja o código:

function Pessoa(nome, sobrenome) {

// var obj = { }

// this = obj

this.nome = nome
this.sobrenome = sobrenome
this.nomeCompleto = function() {
  return this.nome + " " + this.sobrenome
}

// return obj
}

Agora, vamos alterar também a nossa chamada, passando para a função new Pessoa os parâmetros necessários para que a função exerça o seu papel, veja:

var joao = Pessoa()
var maria = new Pessoa('Maria', 'dos Santos')

Perceba que eu só passei parâmetros para a função que está sendo chamada com o operador New!

E por mais que tenhamos alterado totalmente a função, a primeira chamada, no caso a variável ‘joao’, ainda me retorna undefined, enquanto a variável ‘maria’, que passamos o operador New, me retornou todos os dados da função, veja:

undefined Pessoa {
nome: 'Maria',
sobrenome: 'dos Santos',
nomeCompleto: [Function (anonymous)]
}

Agora, vamos alterar a variável ‘joao’ e vamos torná-lo uma função construtora também, passando o operador New antes da chamada da função e informando os parâmetros necessários… Veja:

var joao = new Pessoa('João', 'da Silva')

E agora o node me retorna isso:

Pessoa {
nome: 'João',
sobrenome: 'da Silva',
nomeCompleto: [Function (anonymous)]
} Pessoa {
nome: 'Maria',
sobrenome: 'dos Santos',
nomeCompleto: [Function (anonymous)]
}

Agora, vamos mudar um pouco o cenário e vamos olhar como o Browser está respondendo à isso…

image

Logo de cara, percebemos que o browser me retorna uma propriedade que não é comum… ela se chama Prototype, ou pode ser que apareça como proto.

Mas, o que é então essa propriedade?

Bem… isso nada mais é do que o sistema de heranças do JavaScript funcionando!

Mas vou te explicar minuciosamente como isso acontece… vem comigo!

Quando este novo objeto é criado:

// var obj = { }

Ele herda do Protótipo da classe construtora.

Mas… o que isso significa na prática?

Bem… significa que esse novo objeto:

// var obj = { }

// obj.__proto__ = Pessoa.prototype

Vai receber uma propriedade chamada “Proto”, como você pôde observar no código acima.

E essa propriedade receberá uma referência ao protótipo da classe construtora, que no nosso caso é ‘Pessoa’

E o protótipo dessa classe ‘Pessoa’ nada mais é do que Pessoa.prototype...

Mas você pode se questionar: “Mas eu não declarei esse prototype em lugar nenhum!”

Sim! Esse prototype é criado pelo próprio JavaScript quando você declara QUALQUER f unção…

Então, se você quiser verificar e checar se essa propriedade realmente existe, você pode fazer o seguinte:

console.dir(Pessoa)

E checar no seu DevTools o que o browser está te respondendo, que no caso será isso:

image

E podemos perceber que a função Pessoa realmente possui a propriedade Prototype, mesmo chamando-a como uma função normal…

Mas…

Será que essa propriedade Prototype é realmente o que está sendo referenciado pelo // obj.__proto__ = Pessoa.prototype ?

Vamos testar…

console.log(Pessoa.prototype === joao.__proto__)

E o node me retorna ‘True’.

image

Então, o proto das nossas instâncias realmente está referenciando ao Prototype da nossa função construtora, que no caso é a função ‘Pessoa’!

Mas… porque isso é importante?

Bom… se você reparar nas nossas duas instâncias, cada uma delas está chamando uma função chamada nomeCompleto, como podemos ver na foto abaixo…

image

O que acontece é que, toda vez que você instanciar um novo objeto dessa classe Pessoa, uma nova função está sendo criada e armazenada em memória…

Então, se você estiver criando 100 ou 1000 instâncias dessa mesma classe, você estará desperdiçando processamento e armazenamento porque a cada criação de instância uma nova função é criada e armazenada…

Considerando que essa função faz A MESMA COISA pra todas as instâncias, isso é completamente ineficiente..

Você deveria ter um mecanismo pra que você declarasse essa função uma única vez, ela fosse armazenada na memória somente uma vez e todas as suas instâncias compartilhassem esse método!

E é exatamente pra que isso que serve o protótipo da classe construtora! :)

Vamos fazer o seguinte agora: iremos comentar a nossa função criada dentro de ‘Pessoa’ que retornava o nome + sobrenome e iremos armazená-la dentro do Protoype, veja:

// this.nomeCompleto = function() {
// return this.nome + " " + this.sobrenome
Pessoa.prototype.nomeCompleto = function() {
  return this.nome + " " + this.sobrenome
}

O que fizemos acima foi armazenar aquela função que estava sendo chamada SEMPRE que o objeto ‘Pessoa’ era instanciado dentro do Prototype da função construtora ‘Pessoa’.

Talvez você não tenha entendido o porque, mas, dessa forma, o código não precisa ficar criado toda vez uma nova função sempre que o objeto ‘Pessoa’ for instanciado.

Dessa nova forma, ele apenas referencia do Prototype pra todas as instâncias, ou seja, a função é executada apenas UMA VEZ e todos as instâncias puxam essa informação para si. Esse é o mecanismo de herança do JavaScript acontecendo na prática!

Veja no browser como está sendo a resposta:

image

Como eu disse, agora nossa função está armazenada dentro do Prototype da função construtora, sendo executada apenas uma vez!

Compartilhe
Comentários (3)
Jezyel Passos
Jezyel Passos - 20/08/2022 09:12

Hey Grabriel, parabéns por essa iniciativa de ensinar a comunidade DEVs. Também estou tendo alguns problemas para entender alguns conceitos do JavaScript. Obrigado por compartilhar com a gente o seu aprendizado e suas dicas.

YD

Yure Duarte - 20/08/2022 09:07

Obrigado, finalmente entendi o uso do prototype.

Lucas Henrique
Lucas Henrique - 20/08/2022 08:04

Obrigado, Gabriel!