DEV Community

Cover image for Javascript - Prototypes
Jorge Rafael
Jorge Rafael

Posted on

Javascript - Prototypes

Muito provavelmente você já deve ter ouvido falar em algum lugar que "Tudo no javascript é objeto!", mas por que isso ?

Isso se dá porque praticamente tudo dentro do javascript tem descendência do Object e com isso possuem todos os métodos herdados de Object.prototype.

Mas afinal o que é esse prototype?

O prototype é um objeto que possui um conjunto de métodos que são originais de um tipo, por exemplo o map() ou toString(), que mesmo você não declarando eles na criação da sua variável, ao se deparar com um Array por exemplo eles existem, isso acontece porque quando você declara uma nova variável, você herda as funções do prototype dela.

Exemplo:

const arr = [1, 2, 3];

arr.forEach(() => { });
arr.map(() => { });
arr.hasOwnProperty(0);
Enter fullscreen mode Exit fullscreen mode

Você pode perceber que mesmo não declarando essas funções forEach ou map na criação do nosso Array mesmo assim elas existem, isso porque essas funções são herdadas do Array.prototype; Mas ao olhar dentro do Array.prototype ainda não encontramos o método hasOwnProperty, mas então porque mesmo assim ele existe?

Ele existe porque temos algo chamado Prototype Chain que é o encadeamento de protótipos até o Objeto original.

Quando se trata de herança, o JavaScript tem somente um construtor: objetos. Cada objeto tem um link interno para um outro objeto chamado prototype. Esse objeto prototype também tem um atributo prototype, e assim por diante até o que o valor null seja encontrado como sendo o seu prototype. null que, por definição, não tem prototype, e age como um link final nesta cadeia de protótipos (MDN Web Docs - Herança e cadeia de protótipos (prototype chain))

De forma prática, ao declarar nossa variável arr no exemplo acima nós informamos que o tipo dela é Array, e com isso temos os métodos nativos do Array, que tem um link através do atributo __proto__ para o tipo Object.

// Exemplificando
const arr = [];
arr.__proto__.forEach();
arr.__proto__.__proto__.hasOwnProperty();
// nosso objeto -> prototype do array -> prototype do object. 
Enter fullscreen mode Exit fullscreen mode

Quando usamos o método hasOwnProperty internamente o javascript começa procurar na primeira cadeia de protótipo da nossa variável, ao não encontrar, ele sobe um degrau nessa cadeia, e assim de forma subsequente, até ele encontrar o método ou chegar no tipo primário, se ao chegar no tipo primário ele ainda não encontrar, então é retornado null

const arr = [];

function findFunction (obj, property) { 
    if(obj[property]) return obj[property];
    if(!obj.__proto__) return null;
    findFunction(obj.__proto__, property);
}

findFunction(arr, 'hasOwnProperty')
// arr.hasOwnProperty  - na nossa declaração existe ?
// arr.__proto__.hasOwnProperty - No tipo array existe ?
// arr.__proto__.__proto__.hasOwnProperty - No tipo Object existe ? 
// Se na cadeia acima não existir, então ele retorna null, pois o object é o tipo primário.
Enter fullscreen mode Exit fullscreen mode

"Ah OK, Jorge eu entendi, mas como eu posso tirar proveito do prototype" ?

Existem vários exemplos na internet mostrando como manipular o prototype de uma função que você criou, como exemplo "Carro" ou o clássico exemplo de animais, mas o que eu vou trazer para vocês é um exemplo de manipulação de um Tipo de variável já existente. O que eu mais gosto é o toCapitalize, que não existe nativamente no tipo String, e em nenhum outro, porém muitas vezes precisamos adicionar um capitalize pelo javascript em algum lugar.

Então como funcionaria isso ?

String.prototype.toCapitalize = function () { 
    const words = this.split(' ');
    return words.map((word) => {
        const firstLetter = word[0].toUpperCase();
        const otherLetters = word.substr(1).toLowerCase();
        return `${firstLetter}${otherLetters}`;
    }).join(' ')
}
Enter fullscreen mode Exit fullscreen mode

Simples assim, você cria uma novo método que vai ser vinculado a todos os tipos String do seu código de forma global. (sem que você precise sempre redeclarar essa função);

Mas como eu utilizo?

Ao criar uma variável do tipo array, ela já vai possuir esse método nativamente, daí é só chama-lo da forma abaixo:

"estou no dev.to".toCapitalize()
// Estou No Dev.to
Enter fullscreen mode Exit fullscreen mode

Com esse exemplo, conseguimos ver uma forma "turbinamos" os tipos nativos do Javascript.

!! ATENÇÃO !!

Apesar de ter dado esse exemplo de manipulação de um tipo nativo, tenha muito cuidado, manipular ou sobrescrever métodos de tipo nativos como Array, String, Number etc..., pode gerar confusão na cabeça dos outros desenvolvedores que fizerem parte do projeto que você está implementando. Então, lembre sempre de documentar de forma clara essas mudanças para não ter problemas no futuro.

Espero ter ajudado a esclarecer um pouco mais sobre os mistérios desse mundo do Javascript.

Até a próxima

Referências

Top comments (2)

Collapse
 
rocklee02568 profile image
Ariel Campos

Ótimo texto, espero um dia chegar a criar códigos assim. Obrigado por compartilhar

Collapse
 
kurybr profile image
Jorge Rafael

Com certeza você vai chegar ! Está no caminho certo