Resumo : neste tutorial, você aprenderá sobre o protótipo JavaScript e como ele funciona nos bastidores.
Introdução ao protótipo JavaScript
Em JavaScript, os objetos podem herdar recursos uns dos outros por meio de protótipos . Cada objeto tem sua própria propriedade chamada a prototype
.
Como o prototype
próprio também é outro objeto, o prototype
tem o seu próprio prototype
. Isso cria algo chamado cadeia de protótipos . A cadeia de protótipos termina quando um protótipo tem null
seu próprio protótipo.
Suponha que você tenha um objeto person
com uma propriedade chamada name
:
let person = {'name' : 'John'}
Linguagem de código: JavaScript ( javascript )
Ao examinar o person
objeto no console, você descobrirá que o person
objeto tem uma propriedade chamada prototype
indicada por [[Prototype]]
:
O próprio protótipo é um objeto com propriedades próprias:
Quando você acessa uma propriedade de um objeto, se o objeto tiver essa propriedade, ele retornará o valor da propriedade. O exemplo a seguir acessa a name
propriedade do person
objeto:
Ele retorna o valor da name
propriedade conforme o esperado.
Porém, se você acessar uma propriedade que não existe em um objeto, o mecanismo JavaScript irá pesquisar no protótipo do objeto.
Se o mecanismo JavaScript não conseguir encontrar a propriedade no protótipo do objeto, ele pesquisará no protótipo do protótipo até encontrar a propriedade ou chegar ao final da cadeia de protótipos.
Por exemplo, você pode chamar o toString()
método do person
objeto assim:
O toString()
método retorna a representação em string do person
objeto. Por padrão, é o [object Object]
que não é óbvio.
Observe que quando uma função é um valor da propriedade de um objeto, ela é chamada de método . Portanto, um método é uma propriedade com valor como função.
Neste exemplo, quando chamamos o toString()
método no person
objeto, o mecanismo JavaScript o encontra no person
objeto.
Como o person
objeto não possui o toString()
método, ele procurará o toString()
método no objeto protótipo da pessoa.
Como o protótipo da pessoa possui o toString()
método, o JavaScript chama o toString()
objeto protótipo da pessoa.
Ilustração do protótipo JavaScript
JavaScript tem a função integrada Object()
. O typeof
operador retorna 'function'
se você passar a Object
função para ele. Por exemplo:
typeof(Object)
Linguagem de código: JavaScript ( javascript )
Saída:
'function'
Linguagem de código: JavaScript ( javascript )
Observe que Object()
é uma função, não um objeto. É confuso se esta é a primeira vez que você aprende sobre o protótipo JavaScript.
Além disso, JavaScript fornece um objeto anônimo que pode ser referenciado através da prototype
propriedade da Object()
função:
console.log(Object.prototype);
Linguagem de código: JavaScript ( javascript )
O Object.prototype
objeto possui algumas propriedades e métodos úteis , como toString()
e valueOf()
.
O Object.prototype
também possui uma propriedade importante chamada constructor
que faz referência à Object()
função.
A instrução a seguir confirma que a Object.prototype.constructor
propriedade faz referência à Object
função:
console.log(Object.prototype.constructor === Object); // true
Linguagem de código: JavaScript ( javascript )
Suponha que um círculo represente uma função e um quadrado represente um objeto. A imagem a seguir ilustra a relação entre a Object()
função e o Object.prototype
objeto:
Primeiro, defina uma função construtora chamada Person
da seguinte forma:
function Person(name) {
this.name = name;
}
Linguagem de código: JavaScript ( javascript )
Neste exemplo, a Person()
função aceita um name
argumento e o atribui à name
propriedade do this
objeto.
Nos bastidores, o JavaScript cria uma nova função Person()
e um objeto anônimo:
Assim como a Object()
função, a Person()
função possui uma propriedade chamada prototype
que faz referência a um objeto anônimo. O objeto anônimo possui a constructor
propriedade que faz referência à Person()
função.
O seguinte mostra a Person()
função e o objeto anônimo referenciado por Person.prototype
:
console.log(Person);
console.log(Person.prototype);
Linguagem de código: CSS ( css )
Além disso, o JavaScript vincula o Person.prototype
objeto ao Object.prototype
objeto por meio do [[Prototype]]
, que é conhecido como ligação de protótipo .
A ligação do protótipo é indicada [[Prototype]]
na figura a seguir:
Definindo métodos no objeto protótipo JavaScript
O seguinte define um novo método chamado greet()
no Person.prototype
objeto:
Person.prototype.greet = function() {
return "Hi, I'm " + this.name + "!";
}
Linguagem de código: JavaScript ( javascript )
Neste caso, o mecanismo JavaScript adiciona o greet()
método ao Person.prototype
objeto:
O seguinte cria uma nova instância do Person
:
let p1 = new Person('John');
Linguagem de código: JavaScript ( javascript )
Internamente, o mecanismo JavaScript cria um novo objeto nomeado p1
e vincula o p1
objeto ao Person.prototype
objeto por meio da ligação de protótipo:
O elo entre p1
, Person.prototype
e Object.protoype
é chamado de cadeia de protótipos .
O seguinte chama o greet()
método no p1
objeto:
let greeting = p1.greet();
console.log(greeting);
Linguagem de código: JavaScript ( javascript )
Como p1
não possui o greet()
método, o JavaScript segue a ligação do protótipo e o encontra no Person.prototype
objeto.
Como o JavaScript pode encontrar o greet()
método no Person.prototype
objeto, ele executa o greet()
método e retorna o resultado:
O seguinte chama o toString()
método no p1
objeto:
let s = p1.toString();
console.log(s);
Linguagem de código: JavaScript ( javascript )
Nesse caso, o mecanismo JavaScript segue a cadeia de protótipos para procurar o toString()
método no arquivo Person.prototype
.
Como Person.prototype
não possui o toString()
método, o mecanismo JavaScript vai até a cadeia de protótipos e procura o toString()
método no Object.prototype
objeto.
Como o JavaScript pode encontrar o toString()
método no arquivo Object.prototype
, ele executa o toString()
método.
Se você chamar um método que não existe no objeto Person.prototype
and Object.prototype
, o mecanismo JavaScript seguirá a cadeia de protótipos e gerará um erro se não conseguir encontrar o método. Por exemplo:
p1.fly();
Linguagem de código: CSS ( css )
Como o fly()
método não existe em nenhum objeto da cadeia de protótipos, o mecanismo JavaScript emite o seguinte erro:
TypeError: p1.fly is not a function
Linguagem de código: JavaScript ( javascript )
O seguinte cria outra instância cuja Person
propriedade name é 'Jane'
:
let p2 = new Person('Jane');
Linguagem de código: JavaScript ( javascript )
O p2
objeto possui as mesmas propriedades e métodos que o p1
objeto.
Concluindo, quando você define um método no prototype
objeto, esse método é compartilhado por todas as instâncias.
Definindo métodos em um objeto individual
O seguinte define o draw()
método no p2
objeto.
p2.draw = function () {
return "I can draw.";
};
Linguagem de código: JavaScript ( javascript )
O mecanismo JavaScript adiciona o draw()
método ao p2
objeto, não ao Person.prototype
objeto:
Isso significa que você pode chamar o draw()
método no p2
objeto:
p2.draw();
Linguagem de código: CSS ( css )
Mas você não pode chamar o draw()
método no p1
objeto:
p1.draw()
Linguagem de código: CSS ( css )
Erro:
TypeError: p1.draw is not a function
Linguagem de código: JavaScript ( javascript )
Quando você define um método em um objeto, o método fica disponível apenas para esse objeto. Não pode ser compartilhado com outros objetos por padrão.
Obtendo ligação de protótipo
O __proto__
é pronunciado como dunder proto. The __proto__
é uma propriedade de acesso do Object.prototype
objeto. Ele expõe a ligação do protótipo interno ( [[Prototype]])
de um objeto através do qual ele é acessado.
O __proto__
foi padronizado no ES6 para garantir compatibilidade com navegadores da web. No entanto, pode ser descontinuado em favor de Object.getPrototypeOf()
no futuro. Portanto, você nunca deve usar o __proto__
em seu código de produção.
O p1.__proto__
expõe o [[Prototype]]
que faz referência ao Person.prototype
objeto.
Da mesma forma, p2.__proto__
também faz referência ao mesmo objeto quep1.__proto__:
console.log(p1.__proto__ === Person.prototype); // true
console.log(p1.__proto__ === p2.__proto__); // true
Linguagem de código: JavaScript ( javascript )
Conforme mencionado anteriormente, você deve usar o Object.getPrototypeOf()
método em vez do __proto__
. O Object.getPrototypeOf()
método retorna o protótipo de um objeto especificado.
console.log(p1.__proto__ === Object.getPrototypeOf(p1)); // true
Linguagem de código: JavaScript ( javascript )
Outra forma popular de obter a ligação do protótipo é quando o Object.getPrototypeOf()
método não está disponível por meio da constructor
propriedade como segue:
p1.constructor.prototype
Linguagem de código: CSS ( css )
O p1.constructor
return Person
, portanto, p1.constructor.prototype
retorna o objeto protótipo.
Sombreamento
Veja a seguinte chamada de método:
console.log(p1.greet());
Linguagem de código: CSS ( css )
O p1
objeto não possui o greet()
método definido, portanto o JavaScript sobe até a cadeia de protótipos para encontrá-lo. Neste caso, ele pode encontrar o método no Person.prototype
objeto.
Vamos adicionar um novo método ao objeto p1
com o mesmo nome do método no Person.prototype
objeto:
p1.greet = function() {
console.log('Hello');
}
Linguagem de código: JavaScript ( javascript )
E chame o greet()
método:
console.log(p1.greet());
Linguagem de código: CSS ( css )
Como o p1
objeto possui o greet()
método, o JavaScript apenas o executa imediatamente, sem procurá-lo na cadeia de protótipos.
Este é um exemplo de sombreamento. O greet()
método do p1
objeto obscurece o greet()
método do prototype
objeto ao qual o p1
objeto faz referência.
Resumo
- A
Object()
função possui uma propriedade chamadaprototype
que faz referência a umObject.prototype
objeto. - O
Object.prototype
objeto possui todas as propriedades e métodos que estão disponíveis em todos os objetos, comotoString()
evalueOf()
. - O
Object.prototype
objeto possui aconstructor
propriedade que faz referência àObject
função. - Toda função possui um
prototype
objeto. Este objeto protótipo faz referência aoObject.prototype
objeto por meio[[prototype]]
de ligação ou__proto__
propriedade. - A cadeia de protótipos permite que um objeto use os métodos e propriedades de seus
prototype
objetos por meio de[[prototype]]
ligações. - O
Object.getPrototypeOf()
método retorna o objeto protótipo de um determinado objeto. Use oObject.getPrototypeOf()
método em vez de__proto__
.