Venho estudando bastante sobre JavaScript avançado, e tropecei em Prototype! Considero muito importante entender o funcionamento dele, ao mesmo tempo que parece fácil o entendimento, é meio confuso (pelo menos para mim) aplicar o seu funcionamento.

Vou tentar ser claro e simples com o que entendi!

O que é Prototype?

Antes de explicar o que é, tenho que deixar claro que JavaScript não trabalha com Classe, e sim Construtor! Caso você veja sendo citado Classe em JavaScript em algum lugar da Web, saiba que a pessoa está querendo dizer Construtor… Continuando!

Prototype é forma de conseguir adicionar e acessar Propriedades e Métodos de um Objeto já existente ou que será criado. É ótimo para criar vários Objetos onde você terá um grande controle sobre eles.

A grande jogada de Prototype é poder incluir Métodos de execução a um Objeto, entrando no famoso POO (programação orientada a objetos).

Vamos ver um pouco de código.

function Carro(){
  this.rodas = 4;
}
Carro.prototype.andar = function(algo) {
  return algo;
}
var honda = new Carro();

No exemplo acima, foi criado um Construtor chamado Carro que tem a Propriedade rodas com o valor 4, em seguida foi adicionado ao Prototype um o Método andar que toma algo como parâmetro e o retorna, na linha seguinte criamos um Objeto chamado honda que recebe o Construtor Carro.

Quando você chamar o Objeto honda apenas:

console.log(honda);

Será mostrado apenas a Propriedade rodas e não andar. Porém, se você tentar chamar andar, esse comando irá funcionar perfeitamente. Tente!

console.log(honda.rodas, honda.andar(true));

Mas Igor, ao invés de colocar o Método andar via Prototype, não posso adicioná-lo direto no Construtor? Numa situação pequena como essa, até que pode, mas numa escala maior é melhor via Prototype.

Vamos para um outro exemplo para entender melhor.

function Cachorro(nome, raca, idade) {
  this.nome = nome;
  this.raca = raca;
  this.idade = idade;
}

var bob = new Cachorro('Bob', 'Labrador', '1 ano');
var rex = new Cachorro('Rex', 'Pastor Alemão', '4 anos');

Cachorro.prototype.latir = function() {
  console.log('Som de latido assustador');
}

bob.latir(); // return 'Som de latido assustador'
rex.latir(); // return 'Som de latido assustador'

Entendeu o que aconteceu aí em cima? Existe um Construtor chamado Cachorro e dois Objetos criados em base do Construtor, bob e rex. Perceba que colocamos várias Propriedades, mas para nosso exemplo não iremos usá-los. Em seguida adicionamos o Método latir ao Prototype.

O que quero dizer com todo esse exemplo é que podemos criar mais de 10 mil Objetos com nomes, raças e idades diferentes (que no caso é único para cada cachorro), e o Método latir irá funcionar para todos eles e não irá ter várias repetições do mesmo Método em cada Objeto, já que 1 Prototype será acessado por esses 10 mil cachorros!

Se mudar o Prototype de Cachorro, todos Objetos terão essa alteração.

Fui claro?

Herança ou Cascata?

Alguns falam que Prototype tem o efeito de Herança, outros falam que é efeito Cascata, eu não sei qual é a definição certa, mas acredito e irei seguir a de Cascata.

Na Programação Orientada a Objetos, o efeito Cascata do Prototype permite que você use Métodos e Propriedades de outro Construtor. Podemos pensar que temos um Construtor Animal, que recebe Propriedades que define qualquer característica de um animal, e teremos outro Construtor Macaco que tem dentro dele as características de uma macaco comum, mas que ao mesmo tempo “herda” características do Construtor Animal.

Vamos entender melhor:

function Animal(nome, especie, numPernas) {
  this.nome = nome || 'algum nome';
  this.especie = especie || 'alguma espécie';
  this.numPernas = numPernas || 1000;
}

Animal.prototype.fala = function() {
  console.log('Tenho ' + this.numPernas + ' pernas');
};

function Macaco(especie, numPernas) {
  this.especie = especie;
  this.numPernas = numPernas;
}

Macaco.prototype = new Animal();

var mico = new Macaco('Sagui', 2);

mico.fala();

No exemplo acima, criamos dois Construtores onde Macaco herda Propriedades de Animal, as Propriedades de Macaco que forem iguais a de Animal, serão sobrescritas e as que tiverem em Animal e não tiverem em Macaco, serão acessadas via Prototype.

Por exemplo, se eu quiser acessar o número de pernas do mico, é só passar mico.numPernas que irá me retornar 2, já que definimos na criação do Objeto mico usando o Construtor Macaco, mas se eu quiser usar o Método falar que foi atribuído ao Construtor Animal via Prototype, eu também consigo, já que “herdamos” tudo de Animal dessa forma Macaco.prototype = new Animal();. Então passamos mico.falar() que irá retornar uma string "Tenho 2 patas".

É possível ir criando uma cadeia de Construtores onde cada um vai herdando do outro, essa cadeia pode ter apenas alguns Construtores como vários também, o efeito num gráfico fica igual a uma cascata, daí o nome!

Se o JavaScript não encontrar uma Propriedade ou Método no Construtor atual, ele sobe a cadeia de Prototype até encontrar, ele vai subindo até chegar no topo que é o Object.prototype e se mesmo assim não for encontrado, será retornado undefined.

Por padrão do JavaScript, todo Construtor criado, tem uma “herança” do Object.prototype, então todos Objetos que forem criados usando qualquer Construtor terá por exemplo o Método hasOwnProperty que vem por padrão do Object.prototype.

Bom, chegamos ao fim desse post! Espero que tenha entendido e qualquer dúvida, críticas ou sugestões, será bem vindo aqui nos comentários abaixo.