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.
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.
Cuando leí que todos los objetos integrados como Array, String, etc. son extensiones (heredadas) de Object, supuse que Object es el primer objeto incorporado que se crea y el resto de los objetos hereda de él.
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.
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.
Esto es simplemente falso. Algunos objetos no se crean llamando new Fa alguna función F. 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.
- Cada instancia de objeto tiene un objeto prototipo.
- En algunos casos ese prototipo puede ser
null.
- Si accede a un miembro en una instancia de objeto y el objeto no tiene ese miembro, el objeto se desvía a su prototipo o se detiene si el prototipo es nulo.
- El
prototypemiembro de un objeto generalmente no es el prototipo del objeto.
- Más bien, el
prototypemiembro de un objeto de función F es el objeto que se convertirá en el prototipo del objeto creado por new F().
- En algunas implementaciones, las instancias obtienen un
__proto__miembro que realmente da su prototipo. (Esto ahora está en desuso. No confíe en ello).
- Los objetos de función obtienen un nuevo objeto predeterminado asignado
prototypecuando se crean.
- El prototipo de un objeto de función es, por supuesto
Function.prototype.
Resumamos
- El prototipo de
ObjectesFunction.prototype
Object.prototype es el objeto prototipo de objeto.
- El prototipo de
Object.prototypeesnull
- El prototipo de
Functiones Function.prototype: ¡esta es una de las raras situaciones en las Function.prototypeque en realidad es el prototipo de Function!
Function.prototype es el objeto prototipo de la función.
- El prototipo de
Function.prototypeesObject.prototype
Supongamos que hacemos una función Foo.
- El prototipo de
Fooes Function.prototype.
Foo.prototype es el prototipo de objeto Foo.
- El prototipo de
Foo.prototypees Object.prototype.
Supongamos que decimos new Foo()
- El prototipo del nuevo objeto es
Foo.prototype
Asegúrate de que tenga sentido. Dibujémoslo. Los óvalos son instancias de objeto. Los bordes __proto__significan "el prototipo de" o prototype" 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.
function Car(){ }
var honda = new Car();
print(honda instanceof Car);
print(honda.constructor == Car);
¿Qué imprime esto?
Bueno, que instanceofsignifica? honda instanceof Carsignifica "es Car.prototypeigual a cualquier objeto en hondala cadena de prototipo?"
Sí lo es. hondaEl prototipo es Car.prototype, así que hemos terminado. Esto imprime cierto.
¿Qué hay del segundo?
honda.constructorno existe, por lo que consultamos el prototipo, que es Car.prototype. Cuando Car.prototypese creó el objeto, se le asignó automáticamente una propiedad constructorigual a Car, por lo que esto es cierto.
¿Y qué hay de esto?
var Animal = new Object();
function Reptile(){ }
Reptile.prototype = Animal;
var lizard = new Reptile();
print(lizard instanceof Reptile);
print(lizard.constructor == Reptile);
¿Qué imprime este programa?
Nuevamente, lizard instanceof Reptilesignifica "¿es Reptile.prototypeigual a cualquier objeto en lizardla cadena de prototipo?"
Sí lo es. lizardEl prototipo es Reptile.prototype, así que hemos terminado. Esto imprime cierto.
Ahora, que hay de
print(lizard.constructor == Reptile);
Puede pensar que esto también se imprime como cierto, ya que lizardfue construido con, new Reptilepero estaría equivocado. Razonarlo.
- ¿
lizardTiene una constructorpropiedad? No. Por lo tanto, miramos el prototipo.
- El prototipo de
lizardes Reptile.prototype, que es Animal.
- ¿
AnimalTiene una constructorpropiedad? No. Entonces miramos su prototipo.
- El prototipo de
Animales Object.prototype, y Object.prototype.constructores creado por el tiempo de ejecución e igual a Object.
- Entonces esto imprime falso.
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.
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?
El prototipo de la función se define como una función que, cuando se llama, regresa undefined. Ya sabemos que ese Function.prototypees el Functionprototipo, 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.
cuando de console.log(Function.prototype.constructor)nuevo es una función.
Function.prototype.constructores solo Function, obviamente. Y Functiones una función.
Ahora, ¿cómo puedes usar algo para crearlo tu mismo? (Mente = soplado).
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" y myprototypepara significar "la propiedad prototipo de".
var myobjectprototype = new Object();
var myfunctionprototype = new Object();
myfunctionprototype.my__proto__ = myobjectprototype;
var myobject = new Object();
myobject.myprototype = myobjectprototype;
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.
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.