Este é um modelo de objeto baseado em protótipo muito simples que seria considerado uma amostra durante a explicação, sem comentários ainda:
function Person(name){
this.name = name;
}
Person.prototype.getName = function(){
console.log(this.name);
}
var person = new Person("George");
Há alguns pontos cruciais que devemos considerar antes de passar pelo conceito de protótipo.
1- Como as funções JavaScript realmente funcionam:
Para dar o primeiro passo, precisamos descobrir como as funções JavaScript realmente funcionam, como uma classe como uma função usando this
palavra-chave ou apenas como uma função regular com seus argumentos, o que faz e o que retorna.
Digamos que queremos criar um Person
modelo de objeto. mas nesta etapa tentarei fazer exatamente a mesma coisa sem usar uma palavra prototype
- new
chave .
Portanto, nesta etapa functions
, objects
e this
palavra - chave, são tudo o que temos.
A primeira pergunta seria como a this
palavra-chave poderia ser útil sem usar a new
palavra-chave .
Então, para responder isso, digamos que temos um objeto vazio e duas funções como:
var person = {};
function Person(name){ this.name = name; }
function getName(){
console.log(this.name);
}
e agora sem usar a new
palavra-chave como poderíamos usar essas funções. Portanto, o JavaScript tem três maneiras diferentes de fazer isso:
uma. A primeira maneira é apenas chamar a função como uma função regular:
Person("George");
getName();//would print the "George" in the console
nesse caso, esse seria o objeto de contexto atual, que geralmente é o window
objeto global no navegador ou GLOBAL
no Node.js
. Isso significa que teríamos window.name no navegador ou GLOBAL.name no Node.js, com "George" como seu valor.
b. Podemos anexá- los a um objeto, como suas propriedades
- A maneira mais fácil de fazer isso é modificar o person
objeto vazio , como:
person.Person = Person;
person.getName = getName;
Desta forma, podemos chamá-los como:
person.Person("George");
person.getName();// -->"George"
e agora o person
objeto é como:
Object {Person: function, getName: function, name: "George"}
- A outra maneira de anexar uma propriedade a um objeto é usar o prototype
objeto que pode ser encontrado em qualquer objeto JavaScript com o nome de __proto__
, e tentei explicar um pouco na parte de resumo. Para que pudéssemos obter o resultado semelhante, fazendo:
person.__proto__.Person = Person;
person.__proto__.getName = getName;
Mas, dessa maneira, o que realmente estamos fazendo é modificar o arquivo Object.prototype
, porque sempre que criamos um objeto JavaScript usando literals ( { ... }
), ele é criado com base em Object.prototype
, o que significa que ele é anexado ao objeto recém-criado como um atributo chamado __proto__
, portanto, se o alterarmos , como fizemos no snippet de código anterior, todos os objetos JavaScript seriam alterados, não é uma boa prática. Então, qual poderia ser a melhor prática agora:
person.__proto__ = {
Person: Person,
getName: getName
};
e agora outros objetos estão em paz, mas ainda não parece ser uma boa prática. Portanto, ainda temos mais uma solução, mas, para usá-la, devemos retornar à linha de código em que o person
objeto foi criado ( var person = {};
) e alterá-lo da seguinte forma:
var propertiesObject = {
Person: Person,
getName: getName
};
var person = Object.create(propertiesObject);
o que ele faz é criar um novo JavaScript Object
e anexá propertiesObject
-lo ao __proto__
atributo Portanto, para garantir que você possa fazer:
console.log(person.__proto__===propertiesObject); //true
Mas o ponto complicado aqui é que você tem acesso a todas as propriedades definidas no __proto__
primeiro nível do person
objeto (leia a parte do resumo para obter mais detalhes).
como você vê, usando qualquer uma dessas duas direções this
apontaria exatamente para o person
objeto.
c. O JavaScript tem outra maneira de fornecer a função this
, que está usando call ou apply para invocar a função.
O método apply () chama uma função com um dado valor e argumentos fornecidos como uma matriz (ou um objeto semelhante a uma matriz).
e
O método call () chama uma função com um determinado valor e argumentos fornecidos individualmente.
dessa maneira, que é a minha favorita, podemos chamar facilmente nossas funções como:
Person.call(person, "George");
ou
//apply is more useful when params count is not fixed
Person.apply(person, ["George"]);
getName.call(person);
getName.apply(person);
esses três métodos são as etapas iniciais importantes para descobrir a funcionalidade do protótipo.
2- Como a new
palavra - chave funciona?
este é o segundo passo para entender a .prototype
funcionalidade. é isso que eu uso para simular o processo:
function Person(name){ this.name = name; }
my_person_prototype = { getName: function(){ console.log(this.name); } };
Nesta parte, tentarei executar todas as etapas que o JavaScript executar, sem usar a new
palavra - chave e prototype
, quando você usar a new
palavra-chave. então, quando o fazemos new Person("George")
, a Person
função serve como construtor. É isso que o JavaScript faz, um por um:
uma. Antes de tudo, ele cria um objeto vazio, basicamente um hash vazio como:
var newObject = {};
b. a próxima etapa que o JavaScript executa é anexar todos os objetos de protótipo ao objeto recém-criado
temos my_person_prototype
aqui semelhante ao objeto protótipo.
for(var key in my_person_prototype){
newObject[key] = my_person_prototype[key];
}
Não é assim que o JavaScript realmente anexa as propriedades definidas no protótipo. A maneira atual está relacionada ao conceito de cadeia de protótipos.
uma. & b. Em vez destas duas etapas, você pode obter exatamente o mesmo resultado:
var newObject = Object.create(my_person_prototype);
//here you can check out the __proto__ attribute
console.log(newObject.__proto__ === my_person_prototype); //true
//and also check if you have access to your desired properties
console.log(typeof newObject.getName);//"function"
agora podemos chamar a getName
função em nosso my_person_prototype
:
newObject.getName();
c. então ele fornece esse objeto ao construtor,
podemos fazer isso com nossa amostra como:
Person.call(newObject, "George");
ou
Person.apply(newObject, ["George"]);
então o construtor pode fazer o que quiser, porque esse interior desse construtor é o objeto que acabou de ser criado.
agora o resultado final antes de simular as outras etapas: Objeto {nome: "George"}
Resumo:
Basicamente, quando você usa a nova palavra-chave em uma função, você está chamando isso e essa função serve como construtor; portanto, quando você diz:
new FunctionName()
O JavaScript cria internamente um objeto, um hash vazio e, em seguida, fornece esse objeto ao construtor; então, o construtor pode fazer o que quiser, porque isso dentro desse construtor é o objeto que acabou de ser criado e, em seguida, fornece esse objeto, é claro se você não usou a instrução de retorno em sua função ou se você colocou um return undefined;
no final do corpo da função.
Portanto, quando o JavaScript procura uma propriedade em um objeto, a primeira coisa que faz é procurá-lo nesse objeto. E depois há uma propriedade secreta da [[prototype]]
qual costumamos ter __proto__
e é essa a aparência do JavaScript a seguir. E quando olha através do __proto__
, na medida em que é outro objeto JavaScript, ele tem seu próprio __proto__
atributo, sobe e sobe até chegar ao ponto em que o próximo __proto__
é nulo. O ponto é o único objeto no JavaScript que seu __proto__
atributo é nulo é o Object.prototype
objeto:
console.log(Object.prototype.__proto__===null);//true
e é assim que a herança funciona em JavaScript.
Em outras palavras, quando você tem uma propriedade prototype em uma função e chama uma nova, depois que o JavaScript terminar de examinar o objeto recém-criado por propriedades, ele analisará as propriedades da função .prototype
e também é possível que esse objeto tenha sua propriedade. próprio protótipo interno. e assim por diante.