Javascript - Prototypes
Tags: javascript, prototype, dev, kurybr
Published: 2021-02-26 11:44:13

---
title: Javascript - Prototypes
published: true
description: Muito provavelmente você já deve ter ouvido falar em algum lugar que "Tudo no javascript é objeto!", mas você sabe o porque ?
tags: javascript, prototype, dev, kurybr
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/u2ltfes4c3c8w3fqu1a3.jpeg
---

> 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: 

```javascript
const arr = [1, 2, 3];

arr.forEach(() => { });
arr.map(() => { });
arr.hasOwnProperty(0);
```

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  (<small>[MDN Web Docs - Herança e cadeia de protótipos (prototype chain)](https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Guide/Inheritance_and_the_prototype_chain)</small>)

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.

```javascript
// Exemplificando
const arr = [];
arr.__proto__.forEach();
arr.__proto__.__proto__.hasOwnProperty();
// nosso objeto -> prototype do array -> prototype do object. 
```

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`

```javascript
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.
```

_"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 ?

```javascript
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(' ')
}
```

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:

```javascript
"estou no dev.to".toCapitalize()
// Estou No Dev.to
```

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

<h1> !! ATENÇÃO !! </h1>

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
- [MDN Web Docs - Herança e cadeia de protótipos (prototype chain)](https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Guide/Inheritance_and_the_prototype_chain)
- [MDN Web Docs - Object.prototype](https://developer.mozilla.org/pt-BR/docs/conflicting/Web/JavaScript/Reference/Global_Objects/Object)