Estoy tratando de entender detrás de las escenas de la cortina de Javascript y estoy atascado en la comprensión de la creación de objetos integrados, especialmente Objeto y Función y la relación entre ellos.
Cuando leí que todos los objetos integrados como Array, String, etc. son extensiones (heredadas) de Object, asumí que Object es el primer objeto incorporado que se crea y el resto de los objetos hereda de él. Pero no tiene sentido cuando se llega a saber que los Objetos solo pueden ser creados por funciones, sino que las funciones no son más que objetos de Función. Comenzó a sonar como un dilema de gallina y pollo.
La otra cosa extremadamente confusa es si console.log(Function.prototype)imprimo una función pero cuando imprimo console.log(Object.prototype)imprime un objeto. ¿Por qué es Function.prototypeuna función cuando estaba destinada a ser un objeto?
Además, de acuerdo con la documentación de Mozilla, cada javascript functiones una extensión de Functionobjeto, pero cuando console.log(Function.prototype.constructor)se trata nuevamente de una función. Ahora, ¿cómo puedes usar algo para crearlo tú mismo? (Mente = soplado).
Lo último, Function.prototypees una función, pero puedo acceder a la constructorfunción usando Function.prototype.constructor¿eso significa que Function.prototypees una función que devuelve el prototypeobjeto
fuente

Function.prototypepuede ser una función y tener campos internos. Entonces no, no ejecutas la función prototipo cuando pasas por su estructura. Por último, recuerde que hay un motor de interpretación de Javascript, por lo Objeto y función se crearon probablemente dentro del motor y no de Javascript y referencia especial comoFunction.prototypeyObject.prototypesólo podrían ser interpretados de una manera especial por el motor.Respuestas:
Es complicado, es fácil de entender mal, y muchos libros de JavaScript para principiantes se equivocan, así que no confíes en todo lo que lees.
Fui uno de los implementadores del motor JS de Microsoft en la década de 1990 y en el comité de estandarización, y cometí varios errores al reunir esta respuesta. (Aunque como no he trabajado en esto durante más de 15 años, tal vez pueda ser perdonado). Es algo complicado. Pero una vez que entiendes la herencia del prototipo, todo tiene sentido.
Comience desechando todo lo que sabe sobre la herencia basada en clases. JS utiliza herencia basada en prototipos.
Luego, asegúrese de tener una definición muy clara en su cabeza de lo que significa "herencia". Las personas acostumbradas a lenguajes OO como C # o Java o C ++ piensan que la herencia significa subtipo, pero la herencia no significa subtipo. La herencia significa que los miembros de una cosa también son miembros de otra . ¡No significa necesariamente que haya una relación de subtipo entre esas cosas! Tantos malentendidos en la teoría de tipos son el resultado de que las personas no se dan cuenta de que hay una diferencia.
Esto es simplemente falso. Algunos objetos no se crean llamando
new Fa alguna funciónF. Algunos objetos son creados por el tiempo de ejecución JS de la nada. Hay huevos que no fueron puestos por ningún pollo . Fueron creados por el tiempo de ejecución cuando se inició.Digamos cuáles son las reglas y quizás eso ayude.
null.prototypemiembro de un objeto generalmente no es el prototipo del objeto.prototypemiembro de un objeto de función F es el objeto que se convertirá en el prototipo del objeto creado pornew F().__proto__miembro que realmente da su prototipo. (Esto ahora está en desuso. No confíe en ello).prototypecuando se crean.Function.prototype.Resumamos
ObjectesFunction.prototypeObject.prototypees el objeto prototipo de objeto.Object.prototypeesnullFunctionesFunction.prototype: ¡esta es una de las raras situaciones en lasFunction.prototypeque en realidad es el prototipo deFunction!Function.prototypees el objeto prototipo de la función.Function.prototypeesObject.prototypeSupongamos que hacemos una función Foo.
FooesFunction.prototype.Foo.prototypees el prototipo de objeto Foo.Foo.prototypeesObject.prototype.Supongamos que decimos
new Foo()Foo.prototypeAsegúrate de que tenga sentido. Dibujémoslo. Los óvalos son instancias de objeto. Los bordes
__proto__significan "el prototipo de" oprototype"prototypepropiedad de".Todo lo que el tiempo de ejecución tiene que hacer es crear todos esos objetos y asignar sus diversas propiedades en consecuencia. Estoy seguro de que puedes ver cómo se haría eso.
Ahora veamos un ejemplo que pone a prueba sus conocimientos.
¿Qué imprime esto?
Bueno, que
instanceofsignifica?honda instanceof Carsignifica "esCar.prototypeigual a cualquier objeto enhondala cadena de prototipo?"Sí lo es.
hondaEl prototipo esCar.prototype, así que hemos terminado. Esto imprime cierto.¿Qué hay del segundo?
honda.constructorno existe, por lo que consultamos el prototipo, que esCar.prototype. CuandoCar.prototypese creó el objeto, se le asignó automáticamente una propiedadconstructorigual aCar, por lo que esto es cierto.¿Y qué hay de esto?
¿Qué imprime este programa?
Nuevamente,
lizard instanceof Reptilesignifica "¿esReptile.prototypeigual a cualquier objeto enlizardla cadena de prototipo?"Sí lo es.
lizardEl prototipo esReptile.prototype, así que hemos terminado. Esto imprime cierto.Ahora, que hay de
Puede pensar que esto también se imprime como cierto, ya que
lizardfue construido con,new Reptilepero estaría equivocado. Razonarlo.lizardTiene unaconstructorpropiedad? No. Por lo tanto, miramos el prototipo.lizardesReptile.prototype, que esAnimal.AnimalTiene unaconstructorpropiedad? No. Entonces miramos su prototipo.AnimalesObject.prototype, yObject.prototype.constructores creado por el tiempo de ejecución e igual aObject.Deberíamos haber dicho
Reptile.prototype.constructor = Reptile;en algún momento, ¡pero no nos acordamos!Asegúrate de que todo tenga sentido para ti. Dibuja algunos cuadros y flechas si todavía es confuso.
El prototipo de la función se define como una función que, cuando se llama, regresa
undefined. Ya sabemos que eseFunction.prototypees elFunctionprototipo, por extraño que parezca. Por lo tanto,Function.prototype()es legal, y cuando lo haces,undefinedregresas. Entonces es una función.El
Objectprototipo no tiene esta propiedad; No es invocable. Es solo un objeto.Function.prototype.constructores soloFunction, obviamente. YFunctiones una función.Estás pensando demasiado en esto . Todo lo que se requiere es que el tiempo de ejecución cree un montón de objetos cuando se inicie. Los objetos son solo tablas de búsqueda que asocian cadenas con objetos. Cuando el tiempo de ejecución se pone en marcha, todo lo que tiene que hacer es crear algunos objetos docena de blanco, y luego comenzar a asignar el
prototype,__proto__,constructor, y así sucesivamente propiedades de cada objeto hasta que se haga la gráfica que tienen que hacer.Será útil si tomas el diagrama que te di arriba y le agregas
constructorbordes. Verá rápidamente que este es un gráfico de objetos muy simple y que el tiempo de ejecución no tendrá problemas para crearlo.Un buen ejercicio sería hacerlo usted mismo. Aquí, te comenzaré. Usaremos
my__proto__para significar "el objeto prototipo de" ymyprototypepara significar "la propiedad prototipo de".Y así. ¿Puede completar el resto del programa para construir un conjunto de objetos que tenga la misma topología que los objetos incorporados "reales" de Javascript? Si lo hace, encontrará que es extremadamente fácil.
Los objetos en JavaScript son solo tablas de búsqueda que asocian cadenas con otros objetos . ¡Eso es! No hay magia aquí. Te estás haciendo nudos porque estás imaginando restricciones que en realidad no existen, como si cada objeto tuviera que ser creado por un constructor.
Las funciones son solo objetos que tienen una capacidad adicional: ser llamados. Así que revise su pequeño programa de simulación y agregue una
.mycallablepropiedad a cada objeto que indique si es invocable o no. Es tan simple como eso.fuente
__proto__. El__proto__prototipo del objeto es nulo. El__proto__denew X()esX.prototype. Todos los objetos de función tienen el prototipo de función,__proto__excepto el propio prototipo de función.ObjectyFunctiony el prototipo de la función son funciones. Todas esas reglas son sencillas y determinan la topología de la gráfica de los objetos iniciales.Ya tiene muchas respuestas excelentes, pero solo quiero darle una respuesta breve y clara a su respuesta sobre cómo funciona todo esto, y esa respuesta es:
¡¡¡MAGIA!!!
Realmente, eso es todo.
Las personas que implementan motores de ejecución de ECMAScript tienen que aplicar las reglas de ECMAScript, pero no cumplir por ellos dentro de su aplicación.
La especificación ECMAScript dice que A hereda de B pero B es una instancia de A? ¡No hay problema! Cree A primero con un puntero prototipo de
NULL, cree B como una instancia de A, luego arregle el puntero prototipo de A para señalar B después. Pan comido.Usted dice, pero espere, ¡no hay forma de cambiar el puntero prototipo en ECMAScript! Pero, aquí está la cosa: este código no se está ejecutando en el motor ECMAScript, este código es el motor ECMAScript. Que no tienen acceso a la parte interna de los objetos que el código ECMAScript que se ejecuta en el motor no tiene. En resumen: puede hacer lo que quiera.
Por cierto, si realmente lo desea, solo tiene que hacer esto una vez: luego, por ejemplo, puede volcar su memoria interna y cargar este volcado cada vez que inicie su motor ECMAScript.
Tenga en cuenta que todo esto aún se aplica, incluso si el motor ECMAScript en sí mismo se escribió en ECMAScript (como es el caso de Mozilla Narcissus, por ejemplo). Incluso entonces, el código ECMAScript que implementa el motor todavía tiene acceso completo al motor que está implementando , aunque por supuesto no tiene acceso al motor en el que se está ejecutando .
fuente
De la especificación 1 de ECMA
¡No veo cómo podría estar más claro!
</sarcasm>Más abajo vemos:
Entonces podemos ver que un prototipo es un objeto, pero no necesariamente un objeto de función.
Además, tenemos este interesante titbit
http://www.ecma-international.org/ecma-262/8.0/index.html#sec-object-objects
y
fuente
sarcasmapodo de lo contrario, este texto realmente es bastante opaco para un principiante.Los siguientes tipos abarcan todos los valores en JavaScript:
booleannumberundefined(que incluye el valor únicoundefined)stringsymbol("cosas" abstractas únicas que se comparan por referencia)objectCada objeto (es decir, todo) en JavaScript tiene un prototipo, que es un tipo de objeto.
El prototipo contiene funciones, que también son una especie de objeto 1 .
Los objetos también tienen un constructor, que es una función y, por lo tanto, un tipo de objeto.
Todo es recursivo, pero la implementación puede hacerlo de forma automática porque, a diferencia del código JavaScript, puede crear objetos sin tener que llamar a funciones JavaScript (ya que los objetos son solo memoria que controla la implementación).
La mayoría de los sistemas de objetos en muchos lenguajes de tipo dinámico son circulares 2 como este. Por ejemplo, en Python, las clases son objetos, y la clase de clases es
type, portypelo tanto , es una instancia de sí misma.La mejor idea es usar las herramientas que proporciona el lenguaje y no pensar demasiado en cómo llegaron allí.
1 Las funciones son bastante especiales porque son invocables y son los únicos valores que pueden contener datos opacos (su cuerpo y posiblemente un cierre).
2 En realidad es más una cinta de ramificación torturada doblada hacia atrás sobre sí misma, pero "circular" está lo suficientemente cerca.
fuente