Estou tentando entender os bastidores do Javascript e meio que entendi a criação de objetos embutidos, especialmente Objeto e Função e a relação entre eles.
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. 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. Começou a soar como um dilema de galinha e galinha.
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.prototype
uma função quando deveria ser um objeto?
Além disso, de acordo com a documentação da Mozilla, todo javascript function
é extensão de Function
objeto, mas quando você console.log(Function.prototype.constructor)
é novamente uma função. Agora, como você pode usar algo para criar a si mesmo (Mente = queimado).
Última coisa, Function.prototype
é uma função, mas eu posso acessar a constructor
função usando Function.prototype.constructor
isso significa que Function.prototype
é uma função que retorna o prototype
objeto
fonte
Function.prototype
pode 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.prototype
eObject.prototype
podem ser interpretados de maneira especial pelo mecanismo.Respostas:
É 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.
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.
Isto é simplesmente falso. Alguns objetos não são criados chamando
new F
por alguma funçãoF
. 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.
null
.prototype
membro de um objeto normalmente não é o protótipo do objeto.prototype
membro de um objeto de função F é o objeto que se tornará o protótipo do objeto criado pornew F()
.__proto__
membro que realmente fornece seu protótipo. (Isso agora está obsoleto. Não confie nele.)prototype
serem criados.Function.prototype
.Vamos resumir.
Object
éFunction.prototype
Object.prototype
é o objeto de protótipo de objeto.Object.prototype
énull
Function
éFunction.prototype
- esta é uma das raras situações em queFunction.prototype
é realmente o protótipo deFunction
!Function.prototype
é o objeto de protótipo de função.Function.prototype
éObject.prototype
Vamos supor que façamos uma função Foo.
Foo
éFunction.prototype
.Foo.prototype
é o objeto de protótipo Foo.Foo.prototype
éObject.prototype
.Vamos supor que dizemos
new Foo()
Foo.prototype
Certifique-se de que faz sentido. Vamos desenhar. Ovais são instâncias de objetos. Arestas
__proto__
significam "o protótipo de" ouprototype
significam "aprototype
propriedade 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.
O que isso imprime?
Bem, o que
instanceof
significa?honda instanceof Car
significa "éCar.prototype
igual a qualquer objeto emhonda
cadeia de protótipos?"Sim, ele é.
honda
O protótipo deCar.prototype
, então terminamos. Isso é verdadeiro.E o segundo?
honda.constructor
não existe, então consultamos o protótipo, que éCar.prototype
. Quando oCar.prototype
objeto foi criado, recebeu automaticamente uma propriedadeconstructor
igual aCar
, portanto isso é verdade.Agora e quanto a isso?
O que esse programa imprime?
Novamente,
lizard instanceof Reptile
significa "éReptile.prototype
igual a qualquer objeto nalizard
cadeia de protótipos?"Sim, ele é.
lizard
O protótipo éReptile.prototype
, então terminamos. Isso é verdadeiro.Agora, que tal
Você pode pensar que isso também é verdadeiro, pois
lizard
foi construído com,new Reptile
mas você estaria errado. Razão disso.lizard
umaconstructor
propriedade? Não. Portanto, olhamos para o protótipo.lizard
éReptile.prototype
, que éAnimal
.Animal
umconstructor
propriedade? Não. Então, olhamos para o seu protótipo.Animal
éObject.prototype
eObject.prototype.constructor
é criado pelo tempo de execução e igual aObject
.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.
O protótipo de função é definido como uma função que, quando chamada, retorna
undefined
. Já sabemos que esseFunction.prototype
é oFunction
protótipo, por incrível que pareça. Portanto,Function.prototype()
é legal, e quando você faz isso, vocêundefined
volta. Então é uma função.O
Object
protótipo não possui essa propriedade; não é exigível. É apenas um objeto.Function.prototype.constructor
é apenasFunction
, obviamente. EFunction
é uma função.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
constructor
arestas 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" emyprototype
significar "a propriedade protótipo de".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
.mycallable
propriedade a cada objeto que indique se é possível chamar ou não. É simples assim.fonte
__proto__
. O__proto__
protótipo do objeto é nulo. O__proto__
denew X()
éX.prototype
. Todos os objetos de função possuem o protótipo de função,__proto__
exceto o próprio protótipo de função.Object
eFunction
e o protótipo da função são funções. Essas regras são todas diretas e determinam a topologia do gráfico dos objetos iniciais.Você já tem muitas respostas excelentes, mas só quero dar uma resposta curta e clara à sua resposta sobre como tudo isso funciona, e essa resposta é:
MAGIA!!!
Realmente é isso.
As pessoas que implementam os mecanismos de execução do ECMAScript precisam implementar as regras do ECMAScript, mas não cumpri- las em sua implementação.
A especificação ECMAScript diz que A herda de B, mas B é uma instância de A? Sem problemas! Crie A primeiro com um ponteiro de protótipo de
NULL
, crie B como uma instância de A e, em seguida, corrija o ponteiro de protótipo de A para apontar para B depois. Mole-mole.Você diz, mas espere, não há como alterar o ponteiro do protótipo no ECMAScript! Mas, eis o seguinte: esse código não está sendo executado no mecanismo ECMAScript, esse código é o mecanismo ECMAScript. Ele não têm acesso a partes internas dos objetos que o código ECMAScript funcionamento no motor não tem. Em resumo: ele pode fazer o que quiser.
A propósito, se você realmente quiser, basta fazer isso uma vez: depois, você pode, por exemplo, descarregar sua memória interna e carregá-lo sempre que iniciar o mecanismo ECMAScript.
Observe que tudo isso ainda se aplica, mesmo que o próprio mecanismo ECMAScript tenha sido escrito em ECMAScript (como é realmente o caso do Mozilla Narcissus, por exemplo). Mesmo assim, o código ECMAScript que implementa o mecanismo ainda tem acesso total ao mecanismo que está implementando , embora, é claro, não tenha acesso ao mecanismo em que está sendo executado .
fonte
Da especificação 1 da ECMA
Não vejo como poderia ficar mais claro !!!
</sarcasm>
Mais abaixo, vemos:
Portanto, podemos ver que um protótipo é um objeto, mas não necessariamente um objeto de função.
Além disso, temos esse titbit interessante
http://www.ecma-international.org/ecma-262/8.0/index.html#sec-object-objects
e
fonte
sarcasm
apelido, caso contrário, este texto é realmente bastante opaco para um iniciante.Os seguintes tipos abrangem todos os valores em JavaScript:
boolean
number
undefined
(que inclui o valor únicoundefined
)string
symbol
("coisas" únicas abstratas que são comparadas por referência)object
Todo objeto (ou seja, tudo) no JavaScript possui um protótipo, que é um tipo de objeto.
O protótipo contém funções, que também são um tipo de objeto 1 .
Os objetos também têm um construtor, que é uma função e, portanto, um tipo de objeto.
É tudo recursivo, mas a implementação é capaz de fazer isso automaticamente, porque, diferentemente do código JavaScript, ele pode criar objetos sem precisar chamar funções JavaScript (já que os objetos são apenas memória que a implementação controla).
A maioria dos sistemas de objetos em muitas linguagens dinamicamente tipadas é circular 2 como esta. Por exemplo, no Python, classes são objetos e a classe de classes é
type
, portanto,type
é uma instância de si mesma.A melhor idéia é usar as ferramentas fornecidas pela linguagem e não pensar muito em como elas chegaram lá.
1 As funções são bastante especiais porque são chamadas e são os únicos valores que podem conter dados opacos (seu corpo e possivelmente um fechamento).
2 Na verdade, é mais uma fita torturada e ramificada, dobrada para trás, mas "circular" está perto o suficiente.
fonte