in ,

O que é Prototype Chain em JavaScript.



Nos bastidores, (quase) tudo em JavaScript é um objeto, e se você programou em uma linguagem orientada a objetos como C# e Java, a maneira como JS usa herança pode ser um pouco confusa.

Este artigo discute como implementar padrões de programação orientados a objetos em JavaScript, como: objetos, herança de protótipos, construtores de funções, cadeias de protótipos e herança em subclasses.

Continua após a publicidade..

Quase tudo é um objeto

Por exemplo, ao declarar uma classe, usamos partes do discurso, que são açúcar sintático para protótipos de classe. Em termos de herança, JavaScript tem apenas um construtor: o objeto.

Continua após a publicidade..

Cada objeto tem uma propriedade privada que contém um link para outro objeto chamado protótipo. Este objeto protótipo tem seu próprio protótipo e assim por diante, até que o objeto tenha null como seu protótipo. Por padrão, null não tem protótipo e atua como o último link nesta cadeia de protótipos.

É importante lembrar que quando dizemos “tudo é um objeto” nos referimos a todos os tipos não primitivos. Para entender melhor como funciona a digitação em JS, recomendo a leitura do post que escrevi sobre a diferença entre valores e referências em JavaScript.

Continua depois da Publicidade

A palavra-chave usada em muitas linguagens de programação para criar esses objetos é class. Você define uma classe com um construtor e várias funções públicas e privadas. Se você quiser que uma classe herde de outra, escreva uma sintaxe de herança e (uau!), crie uma cadeia de herança.

No entanto, JavaScript é conhecido como programação baseada em protótipo e é um estilo de programação orientado a objetos no qual não temos classes. Em vez disso, a reutilização comportamental (equivalente à herança em linguagens baseadas em classes) é alcançada através do processo de decoração (ou extensão) de objetos existentes usados ​​como protótipos. Esse modelo também é conhecido como programação sem classes, orientada a protótipos ou baseada em exemplos.

O exemplo original (e mais canônico) de uma linguagem baseada em protótipo é a linguagem de autoprogramação desenvolvida por David Ungar e Randall Smith. No entanto, o estilo de programação classless tornou-se mais popular e adotado por linguagens de programação como JavaScript, Cecil, NewtonScript, lo, MOO, REBOL, Kevo, Squeak, etc.

Temos alguns pontos de discórdia neste ponto, pois muitos veem isso como uma fraqueza, mas na minha opinião esse padrão de herança é, em última análise, mais poderoso que o padrão clássico. Cada objeto é como uma caixa cheia de propriedades, cada uma ligada ao seu próprio protótipo.

Vale lembrar que hoje temos classes em JavaScript, mas é apenas uma sintaxe sugar com algumas diferenças que sugiro que dê uma olhada aqui. Em outras palavras, em JavaScript temos pseudo-classes

Acho que é isso que você está pensando, haha. Bem, vamos tentar iniciar o aquecimento, vamos analisar o seguinte exemplo:

const myObject = {
name: ‘Celso’,
sign: ‘capricorn’
}

function mySign() {
return myObject.sign
}

Declaramos um objeto chamado myObject e uma função chamada mySign. Se executarmos no console do navegador, veja abaixo:

Observe dois pontos importantes aqui, quando chamamos myObject.__proto__, ele retorna um objeto (com alguns parâmetros que analisaremos posteriormente), e outro ponto importante é: mySign.__proto__, que retorna uma função.

Vamos analisar o diagrama abaixo para entender melhor essa conexão.

O que está acontecendo nos bastidores é que a constante myObject tem um link para o protótipo de object.prototype , que é o último item dessa cadeia, porque null por definição não tem protótipo e, em última análise, atua como essa cadeia de protótipos.

Mas como Celso funciona?

Vamos dar uma olhada mais profunda em como seria uma cadeia combinando os dois.

Quando usamos a função map, ela retorna outro objeto baseado no parâmetro passado. Mas de onde vem o recurso de mapa?

Temos as seguintes matrizes:

const myArray = [1, 2, 3, ‘Celso’]

Vamos analisar a imagem acima, o que encontramos chamando essa constante no console do navegador.

Temos todos os nós declarados em myArray , mas temos um ponto especial, também temos um nó chamado __proto__ . Dentro deles, temos todos os métodos disponíveis para arrays, entre eles map, forEach, push, reduce, slice, etc.

Se você perceber que dentro do construtor temos a função Array, quando criamos o array com new Array ou const arr = [], ambos estarão vinculados ao protótipo do método array, onde o método é exposto conforme descrito acima e também mostrado na imagem.

Com isso, a cadeia de protótipos verifica se o método está contido no objeto, o próximo não é pesquisado e assim sucessivamente.

Geralmente sempre trabalhamos com muitos objetos ou arrays, então uma boa prática é manter alguns elementos imutáveis, vamos discutir um exemplo:

const myObject = {
ownersName: ‘Celso’,
dogName: [‘Maya’, ‘Bacon’, ‘Paçoca’, ‘Pandora’, ‘Rex’],
};

myObject.amount = myObject.dogName.length;

const newObject = myObject;
newObject.amount = 2;
console.log(myObject.amount + newObject.amount);

Analisando o código acima, na linha 1 criamos a constante myObject, que possui duas propriedades, onwnerName e dogName. Na linha 6, criamos a propriedade amount que recebe o valor total da propriedade dogName, temos um total de 5 itens. Na linha 8, criamos uma nova constante newObject que recebe myObject, e na linha 9 definimos o valor da quantidade da nova constante newObject para 2.

Isso é muita confusão para muitos programadores, pois muita gente aqui acha que console.log vai retornar o valor 7 na linha 10, certo? Bem, se é isso que você está pensando, você está errado.

O resultado que acontece neste caso é o valor 4, por que isso está acontecendo? , ao criar a constante newObject e atribuir myObject na linha 8, em Javascript não cria uma nova referência para myObject , e na linha 9 modificamos a quantidade para 2, então a quantidade de newObject e myObject é definida como 2.

Se você já lidou com qualquer estrutura de gerenciamento de estado. Você saberá que a imutabilidade é muito importante. Deixe-me explicar brevemente. Objetos imutáveis ​​são objetos cujo estado não pode ser modificado após a criação. O problema com JavaScript é que os arrays são mutáveis.

Nem tudo são flores né

Sim, a vida é uma caixa surpresa rsrs, dependendo do tamanho da árvore da cadeia protótipo, podemos ter problemas de desempenho, como isso pode acontecer? Ao fazer qualquer pesquisa de método, ele pode não encontrar um método dentro do objeto, ele passa para o próximo método, e assim sucessivamente, até chegar ao último nó desta cadeia. Também pode acontecer de declararmos vários outros objetos, um dos quais também herda de outros objetos, criando uma cadeia muito grande, o que gera muitos gargalos em sua execução, o que traz problemas de desempenho.

e como saber se esse método existe no seu objeto e não na cadeia de protótipos. No próprio objeto temos um método chamado hasOwnProperty que verifica se a propriedade faz parte do objeto.

Veja o exemplo abaixo:

const array = [1, 2, 3, 4, 5];

console.log(array.hasOwnProperty(‘1’));
console.log(array.hasOwnProperty(‘map’));
console.log(array.__proto__.hasOwnProperty(‘map’));

Na linha 3 verificamos se temos uma propriedade “1”, dentro desse objeto ele retorna true, na linha 4 verificamos se temos uma propriedade map, retorna false, na linha 5 retorna true , pois a propriedade map não existe dentro deste objeto e existe no protótipo que será um array a seguir.

Acho que hoje temos muitas informações, sim, vou compartilhar esse post e vamos parar por aí. No próximo artigo, veremos outras maneiras de usar a POO.

5 dicas para se tornar ninja em JavaScript

5 tópicos úteis para usar em React apps com Firebase e Firestore