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.prototype
una función cuando estaba destinada a ser un objeto?
Además, de acuerdo con la documentación de Mozilla, cada javascript function
es una extensión de Function
objeto, 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.prototype
es una función, pero puedo acceder a la constructor
función usando Function.prototype.constructor
¿eso significa que Function.prototype
es una función que devuelve el prototype
objeto
fuente
Function.prototype
puede 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.prototype
yObject.prototype
só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 F
a 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
.prototype
miembro de un objeto generalmente no es el prototipo del objeto.prototype
miembro 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).prototype
cuando se crean.Function.prototype
.Resumamos
Object
esFunction.prototype
Object.prototype
es el objeto prototipo de objeto.Object.prototype
esnull
Function
esFunction.prototype
: ¡esta es una de las raras situaciones en lasFunction.prototype
que en realidad es el prototipo deFunction
!Function.prototype
es el objeto prototipo de la función.Function.prototype
esObject.prototype
Supongamos que hacemos una función Foo.
Foo
esFunction.prototype
.Foo.prototype
es el prototipo de objeto Foo.Foo.prototype
esObject.prototype
.Supongamos que decimos
new Foo()
Foo.prototype
Asegúrate de que tenga sentido. Dibujémoslo. Los óvalos son instancias de objeto. Los bordes
__proto__
significan "el prototipo de" oprototype
"prototype
propiedad 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
instanceof
significa?honda instanceof Car
significa "esCar.prototype
igual a cualquier objeto enhonda
la cadena de prototipo?"Sí lo es.
honda
El prototipo esCar.prototype
, así que hemos terminado. Esto imprime cierto.¿Qué hay del segundo?
honda.constructor
no existe, por lo que consultamos el prototipo, que esCar.prototype
. CuandoCar.prototype
se creó el objeto, se le asignó automáticamente una propiedadconstructor
igual aCar
, por lo que esto es cierto.¿Y qué hay de esto?
¿Qué imprime este programa?
Nuevamente,
lizard instanceof Reptile
significa "¿esReptile.prototype
igual a cualquier objeto enlizard
la cadena de prototipo?"Sí lo es.
lizard
El 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
lizard
fue construido con,new Reptile
pero estaría equivocado. Razonarlo.lizard
Tiene unaconstructor
propiedad? No. Por lo tanto, miramos el prototipo.lizard
esReptile.prototype
, que esAnimal
.Animal
Tiene unaconstructor
propiedad? No. Entonces miramos su prototipo.Animal
esObject.prototype
, yObject.prototype.constructor
es 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.prototype
es elFunction
prototipo, por extraño que parezca. Por lo tanto,Function.prototype()
es legal, y cuando lo haces,undefined
regresas. Entonces es una función.El
Object
prototipo no tiene esta propiedad; No es invocable. Es solo un objeto.Function.prototype.constructor
es soloFunction
, obviamente. YFunction
es 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
constructor
bordes. 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" ymyprototype
para 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
.mycallable
propiedad 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.Object
yFunction
y 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
sarcasm
apodo de lo contrario, este texto realmente es bastante opaco para un principiante.Los siguientes tipos abarcan todos los valores en JavaScript:
boolean
number
undefined
(que incluye el valor únicoundefined
)string
symbol
("cosas" abstractas únicas que se comparan por referencia)object
Cada 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
, portype
lo 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