Estou tentando entender os bastidores do Javascript e meio que entendi a criação de objetos incorporados, especialmente Objeto e Função e a relação entre eles.
É complicado, é fácil entender mal, e muitos livros Javascript para iniciantes entendem errado, portanto, não confie em tudo que lê.
Eu fui um dos implementadores do mecanismo JS da Microsoft na década de 90 e no comitê de padronização, e cometi vários erros ao montar essa resposta. (Embora eu não trabalhe nisso há mais de 15 anos, talvez eu possa ser perdoado.) É uma coisa complicada. Mas depois que você entende a herança do protótipo, tudo faz sentido.
Quando li que todos os objetos incorporados, como Array, String etc., são extensão (herdada) do Object, assumi que Object é o primeiro objeto incorporado que é criado e o restante dos objetos herda.
Comece jogando fora tudo o que você sabe sobre herança baseada em classe. JS usa herança baseada em protótipo.
Em seguida, verifique se você tem uma definição muito clara do que "herança" significa. As pessoas acostumadas a linguagens OO como C # ou Java ou C ++ acham que herança significa subtipagem, mas herança não significa subtipagem. Herança significa que os membros de uma coisa também são membros de outra coisa . Isso não significa necessariamente que exista uma relação de subtipagem entre essas coisas! Muitos mal-entendidos na teoria dos tipos são o resultado de pessoas que não percebem que há uma diferença.
Mas não faz sentido quando você descobre que os Objetos só podem ser criados por funções, mas as funções também não passam de objetos da Função.
Isto é simplesmente falso. Alguns objetos não são criados chamando new Fpor alguma função F. Alguns objetos são criados pelo tempo de execução JS do nada. Existem ovos que não foram postos por nenhuma galinha . Eles foram criados apenas pelo tempo de execução quando ele foi iniciado.
Digamos quais são as regras e talvez isso ajude.
- Toda instância de objeto possui um objeto de protótipo.
- Em alguns casos, esse protótipo pode ser
null.
- Se você acessar um membro em uma instância de objeto e o objeto não tiver esse membro, o objeto será diferido para seu protótipo ou será interrompido se o protótipo for nulo.
- O
prototypemembro de um objeto normalmente não é o protótipo do objeto.
- Em vez disso, o
prototypemembro de um objeto de função F é o objeto que se tornará o protótipo do objeto criado pornew F() .
- Em algumas implementações, as instâncias obtêm um
__proto__membro que realmente fornece seu protótipo. (Isso agora está obsoleto. Não confie nele.)
- Os objetos de função recebem um novo objeto padrão atribuído ao
prototypeserem criados.
- O protótipo de um objeto de função é, é claro
Function.prototype.
Vamos resumir.
- O protótipo de
ObjectéFunction.prototype
Object.prototype é o objeto de protótipo de objeto.
- O protótipo de
Object.prototypeénull
- O protótipo de
Functioné Function.prototype- esta é uma das raras situações em que Function.prototypeé realmente o protótipo de Function!
Function.prototype é o objeto de protótipo de função.
- O protótipo de
Function.prototypeéObject.prototype
Vamos supor que façamos uma função Foo.
- O protótipo de
Fooé Function.prototype.
Foo.prototype é o objeto de protótipo Foo.
- O protótipo de
Foo.prototypeé Object.prototype.
Vamos supor que dizemos new Foo()
- O protótipo do novo objeto é
Foo.prototype
Certifique-se de que faz sentido. Vamos desenhar. Ovais são instâncias de objetos. Arestas __proto__significam "o protótipo de" ou prototypesignificam "a prototypepropriedade de".

Tudo o que o tempo de execução precisa fazer é criar todos esses objetos e atribuir suas várias propriedades de acordo. Tenho certeza que você pode ver como isso seria feito.
Agora vamos ver um exemplo que testa seu conhecimento.
function Car(){ }
var honda = new Car();
print(honda instanceof Car);
print(honda.constructor == Car);
O que isso imprime?
Bem, o que instanceofsignifica? honda instanceof Carsignifica "é Car.prototypeigual a qualquer objeto emhonda cadeia de protótipos?"
Sim, ele é. hondaO protótipo deCar.prototype , então terminamos. Isso é verdadeiro.
E o segundo?
honda.constructornão existe, então consultamos o protótipo, que é Car.prototype. Quando o Car.prototypeobjeto foi criado, recebeu automaticamente uma propriedade constructorigual a Car, portanto isso é verdade.
Agora e quanto a isso?
var Animal = new Object();
function Reptile(){ }
Reptile.prototype = Animal;
var lizard = new Reptile();
print(lizard instanceof Reptile);
print(lizard.constructor == Reptile);
O que esse programa imprime?
Novamente, lizard instanceof Reptilesignifica "é Reptile.prototypeigual a qualquer objeto na lizardcadeia de protótipos?"
Sim, ele é. lizardO protótipo éReptile.prototype , então terminamos. Isso é verdadeiro.
Agora, que tal
print(lizard.constructor == Reptile);
Você pode pensar que isso também é verdadeiro, pois lizardfoi construído com, new Reptilemas você estaria errado. Razão disso.
- Tem
lizarduma constructorpropriedade? Não. Portanto, olhamos para o protótipo.
- O protótipo de
lizardé Reptile.prototype, que é Animal.
- Tem
Animalumconstructor propriedade? Não. Então, olhamos para o seu protótipo.
- O protótipo de
Animalé Object.prototypee Object.prototype.constructoré criado pelo tempo de execução e igual a Object.
- Então isso é falso.
Deveríamos ter dito Reptile.prototype.constructor = Reptile;em algum momento, mas não nos lembramos!
Certifique-se de que tudo faça sentido para você. Desenhe algumas caixas e setas se ainda estiver confuso.
A outra coisa extremamente confusa é que, se eu console.log(Function.prototype)imprime uma função, mas quando imprimo console.log(Object.prototype), imprime um objeto. Por que Function.prototypeuma função quando deveria ser um objeto?
O protótipo de função é definido como uma função que, quando chamada, retorna undefined. Já sabemos que esse Function.prototypeé o Functionprotótipo, por incrível que pareça. Portanto, Function.prototype()é legal, e quando você faz isso, você undefinedvolta. Então é uma função.
O Objectprotótipo não possui essa propriedade; não é exigível. É apenas um objeto.
quando você console.log(Function.prototype.constructor)é novamente uma função.
Function.prototype.constructoré apenas Function, obviamente. E Functioné uma função.
Agora, como você pode usar algo para criar a si mesmo (Mente = queimado).
Você está pensando demais nisso . Tudo o que é necessário é que o tempo de execução crie vários objetos ao iniciar. Objetos são apenas tabelas de pesquisa que associam seqüências de caracteres a objetos. Quando o tempo de execução inicia-se, tudo o que tem a fazer é criar alguns objetos dúzia em branco e, em seguida, começar a atribuir a prototype, __proto__, constructor, e assim por diante propriedades de cada objeto até que eles fazem o gráfico que eles precisam fazer.
Será útil se você pegar o diagrama que eu lhe dei acima e adicionar constructorarestas a ele. Você verá rapidamente que este é um gráfico de objeto muito simples e que o tempo de execução não terá problemas para criá-lo.
Um bom exercício seria fazer você mesmo. Aqui, eu vou começar você. Usaremos my__proto__para significar "o objeto protótipo de" e myprototypesignificar "a propriedade protótipo de".
var myobjectprototype = new Object();
var myfunctionprototype = new Object();
myfunctionprototype.my__proto__ = myobjectprototype;
var myobject = new Object();
myobject.myprototype = myobjectprototype;
E assim por diante. Você pode preencher o restante do programa para construir um conjunto de objetos com a mesma topologia dos objetos internos "reais" do Javascript? Se você fizer isso, verá que é extremamente fácil.
Objetos em JavaScript são apenas tabelas de pesquisa que associam seqüências de caracteres a outros objetos . É isso aí! Não há mágica aqui. Você está se amarrando porque está imaginando restrições que realmente não existem, como se todo objeto tivesse que ser criado por um construtor.
Funções são apenas objetos que possuem uma capacidade adicional: a serem chamados. Portanto, siga seu pequeno programa de simulação e adicione uma .mycallablepropriedade a cada objeto que indique se é possível chamar ou não. É simples assim.
Function.prototypepode ser uma função e ter campos internos. Portanto, não, você não executa a função prototype ao passar por sua estrutura. Por fim, lembre-se de que existe um mecanismo para interpretar Javascript; portanto, Objeto e Função provavelmente são criados dentro do mecanismo e não a partir de Javascript e referências especiais comoFunction.prototypeeObject.prototypepodem ser interpretados de maneira especial pelo mecanismo.