Para entender o protótipo no JS, você deve primeiro entender os seguintes conceitos
1. Tudo no JS é um objeto
2. Tudo no JS é derivado do objeto, ou seja, o ponto final da cadeia de protótipo de todas as coisas aponta para objeto.prototipo
// ["Construtor", "ToString", "Tolocalestring", "Valueof", "HasownProperty", "Isprototypeof", // "Propertyisenumerable", "__definegetter__", "__lookUpgetter__", "__defineStter__", "/" __lochester, " console.log (object.getownPropertyNames (object.prototype));
3. A relação sutil entre construtores e instâncias (objetos) em JS
Os construtores definem protótipos para concordar com as especificações de suas instâncias e, em seguida, construir instâncias por meio de novas. Sua função é produzir objetos.
O construtor (método) em si é uma instância do método (função), portanto também pode ser encontrado para o seu __proto __ (Protochain)
Objeto / função f () {} Este é o construtor, um é fornecido pela API nativa do JS, e o outro é personalizado
novo objeto () / novo f () é uma instância
Os exemplos só podem ser vistos "apenas" para descobrir em qual protótipo ele é feito com base.
O protótipo que "não pode" redefine a instância e depois se ilude para criar uma instância da instância.
Pratique produzir conhecimento verdadeiro, e somente observando/pensando em si mesmo, você pode realmente entender:
// Vamos primeiro olhar para o que o construtor é // function empty () {} function empty () {} console.log (function.prototype, function .__ proto__); // objeto {} função empty () {} console.log (object.prototype, object .__ proto__); função f () {} // f {} função vazio () {} console.log (f.prototype, f .__ proto__);Você pode estar tonto, vamos quebrá -lo.
protótipo
O formato da saída do protótipo é: protótipo de nome do construtor
Primeiro, vamos dar uma olhada em qual objeto.Prototype as saídas?
Objeto {} -> O objeto anterior é o nome do construtor e o próximo representa o protótipo. Aqui está um {}, ou seja, uma instância de um objeto (objeto vazio)
Então f {} entendemos o que isso significa. F é o nome do construtor, e o protótipo também é um objeto vazio
// Vamos dar uma olhada no exemplo construído pelo construtor var o = new Object (); // var o = {}; // objeto indefinido {} console.log (o.prototype, o .__ Proto__); função f () {} var i = new f (); // indefinido f {} console.log (i.prototype, i .__ proto__);Vamos um pouco mais fundo e definir o protótipo de F para ver o que acontecerá?
função f () {} f.prototype.a = function () {}; var i = novo f (); // indefinido f {a: function} console.log (i.prototype, i .__ proto__);Dessa maneira, podemos ver claramente que eu é construído a partir de f, o protótipo é {a: function}, o que significa que um método a foi adicionado ao protótipo de objeto vazio original.
Vamos mudar a situação, o que acontecerá se o protótipo que cobre completamente F?
função f () {} f.prototype = {a: function () {}}; var i = novo f (); // objeto indefinido {a: function} console.log (i.prototype, i .__ proto__);Ei ~ Por que isso indica aqui que eu é construído a partir do objeto? Não!
Como substituímos completamente o protótipo de F, especificamos o protótipo como um objeto {a: function}, mas isso fará com que as informações originais do construtor sejam perdidas e se tornem o construtor especificado pelo objeto {a: function}.
Então, qual é o construtor do objeto {a: function}?
Porque o objeto {a: function} é realmente relativo a
var o = {a: function () {}} // novo objetoEntão o construtor de O é obviamente um objeto
Vamos corrigir este erro
função f () {} f.prototype = {a: function () {}} // re-specy o construtor correto f.prototype.constructor = f; var i = novo f (); // indefinido f {a: function, construtor: function} console.log (i.prototype, i .__ proto__);Agora você pode obter as informações corretas do protótipo novamente ~
Cadeia de protótipo
Então vamos dar uma olhada em que cadeia de protótipos é?
Simplificando, é o mesmo que a relação de herança (cadeia) na OOP. Procure a camada por camada até o objeto final.prototipo
O mais importante é descobrir quais são as coisas no JS (instâncias) objetos. Isso é simples, tudo em JS é objetos!
Então precisamos descobrir que qualquer objeto tem um protótipo!
Então vamos provar isso:
Objeto // Esta é uma função, a função é um objeto de instância da função; portanto, é o objeto .__ proto__ == function.prototype // Então o protótipo do objeto, true // esse é um objeto comum; portanto, a instância do objeto pertence à função. Object.prototype .__ proto__ == null // função true // Esta também é uma função, sim! Função .__ proto__ == function.prototype // função true a () {} // Esta é uma função personalizada, e ainda é uma função, afinal, isso mesmo! A .__ proto__ == function.prototype // Alguma função é uma instância de função, assim como o protótipo de A? var a = novo a () a .__ proto__ == a.prototype // A instância a é construído pelo construtor A; portanto, um protótipo de a é definido pelo atributo protótipo de a.prototype .__ proto__ == object.prototype // Exemplo de objetos ordinários são objetos são objetosProtótipo e __proto__
Cada objeto contém um __proto__ apontando para o "protótipo" do objeto.
Uma coisa semelhante é que cada função contém um protótipo. Para que serve esse protótipo objeto?
Vejamos o código a seguir, usando o construtor para criar um objeto (o acima é criar um objeto na forma de uma forma literal).
function foo () {}; var foo = new Foo (); console.log (foo .__ proto__);Imagine: o que o __proto__ deste objeto Foo apontará?
Um objeto que contém o atributo construtor? Não importa se você não entende muito. Imprima o atributo protótipo da função Foo e compare -o com você para saber.
function foo () {}; var foo = new Foo (); console.log (foo .__ proto __); console.log (foo.prototype); console.log (foo .__ proto__ === foo.prototype);Acontece que o __proto__ do objeto Foo que sai de novos pontos apenas para o protótipo da função Foo.
foo .__ Proto__ -> foo.prototype
Qual é o sentido de projetar JS assim? Lembrando o que foi mencionado acima, no mundo dos JS, os objetos não são criados com base nas classes (moldes), mas são derivados de protótipos (outro objeto).
Quando realizamos novas operações para criar um novo objeto, não abordaremos a implementação específica de novas operações, mas temos certeza de uma coisa - ou seja, apontamos para um protótipo objeto para o novo objeto __proto__.
Apenas este código
function foo () {}; var foo = new Foo ();Para quem é o proto__ proto__ apontando? Por que você não pode apontar para a função Foo? Embora a função também seja um objeto, falarei sobre isso em detalhes se você tiver a chance. Mas certamente não é apropriado apontar para foo .__ Proto__Foo, porque Foo é uma função com muito código lógico. Como objeto, ele não tem significado para herdar processamento lógico. O que deseja herdar é o atributo do "objeto de protótipo".
Portanto, cada função gerará automaticamente um objeto de protótipo e o __proto__ do objeto novo dessa função aponta para o protótipo desta função.
foo .__ Proto__ -> foo.prototype
Resumir
Depois de dizer tanto, ainda não expliquei completamente, então é melhor estar na foto anterior. Referenciei fotos de outros internautas, mas sempre sinto que não expliquei com clareza, então tirei uma foto. Se eu acho que o meu é bom, goste! (Eu tentei o meu melhor para desenhá -lo).
Vamos tirar essa foto e lembrar dos seguintes fatos:
1. Existe um atributo _proto_ em cada objeto.
Não há conceito de classe (mofo) no mundo JS. Os objetos são derivados de outro objeto (proto); portanto, haverá um atributo _proto_ em cada objeto apontando para seu objeto de protótipo. (Consulte o objeto Obj definido em forma literal no canto superior esquerdo. Ele abre um espaço para armazenar as próprias propriedades do objeto na memória e gera um _proto_ apontando para o seu protótipo - o objeto de protótipo de nível superior.)
2. Cada função possui uma propriedade de protótipo.
Por que o "construtor" é chamado de construtor? Porque deseja construir um objeto. Então, de acordo com o primeiro fato acima, para quem o atributo _proto_ do novo objeto construído aponta? Você não pode apontar para o próprio construtor. Embora também seja um objeto, você não deseja que o novo objeto herde as propriedades e métodos da função. Portanto, cada construtor terá um atributo de protótipo, apontando para um objeto como o protótipo do novo objeto construído por esse construtor.
3. As funções também são objetos.
Cada função possui algumas propriedades e métodos comuns, como Apply ()/Call (), etc. Mas como esses métodos comuns são herdados? Como as funções são criadas? Imagine, tudo é um objeto, incluindo funções, e é um objeto construído através de um construtor. Então, de acordo com o segundo fato acima, cada função também terá um protótipo apontando para o seu construtor. A função deste construtor é a função e todas as funções em JS são construídas a partir da função. As propriedades e métodos gerais de funções são armazenados na função do objeto de protótipo.Prototype.