
Las siguientes cuatro líneas son suficientes para confundir a la mayoría de los desarrolladores de JavaScript:
Object instanceof Function//true
Object instanceof Object//true
Function instanceof Object//true
Function instanceof Function//true
El prototipo en JavaScript es uno de los conceptos más alucinantes, pero no puede evitarlo. No importa cuánto lo ignore, encontrará el rompecabezas prototipo durante su vida de JavaScript.
Así que enfrentémoslo de frente.
Comenzando con lo básico, existen los siguientes tipos de datos en JavaScript:
- indefinido
- nulo
- número
- cuerda
- booleano
- objeto
Los primeros cinco son tipos de datos primitivos. Estos almacenan un valor de su tipo, como un booleano, y pueden ser verdaderos o falsos .
El último "objeto" es un tipo de referencia que podemos describir como una colección de pares clave-valor (pero es mucho más).
En JavaScript, los nuevos objetos se crean utilizando la función de constructor de objetos (o literal de objeto ) que proporciona métodos genéricos como y .{}
toString()
valueOf()
Las funciones en JavaScript son objetos especiales que se pueden " llamar" . Los hacemos y usando la función constructora de Función (o función literal). El hecho de que estos constructores sean objetos además de funciones siempre me ha confundido, de la misma manera que el acertijo del huevo y la gallina confunde a todos.
Antes de comenzar con Prototipos, quiero aclarar que existen dos prototipos en JavaScript:
- prototipo : este es un objeto especial que se asigna como propiedad de cualquier función que realice en JavaScript. Déjame ser claro aquí, ya está presente para cualquier función que hagas, pero no es obligatorio para las funciones internas proporcionadas por JavaScript (y la función devuelta por
bind
). Esteprototype
es el mismo objeto al que apunta el[[Prototype]]
(ver más abajo) de un objeto recién creado a partir de esa función (usando lanew
palabra clave). - [[Prototipo]]: Esta es una propiedad de alguna manera oculta en cada objeto al que accede el contexto en ejecución si alguna propiedad que se está leyendo en el objeto no está disponible. Esta propiedad es simplemente una referencia a la
prototype
de la función a partir de la cual se hizo el objeto. Se puede acceder a él en un script usando un getter-setter especial (tema para otro día) llamado__proto__
. Hay otras formas nuevas de acceder a este prototipo, pero en aras de la brevedad, me referiré a[[Prototype]]
usando__proto__
.
var obj = {}var obj1 = new Object()
Las dos declaraciones anteriores son declaraciones iguales cuando se utilizan para crear un nuevo objeto, pero suceden muchas cosas cuando ejecutamos cualquiera de estas declaraciones.
Cuando hago un objeto nuevo, está vacío. En realidad, no está vacío porque es una instancia delObject
constructor, y obtiene inherentemente una referencia de prototype
de Object,
que es señalado por el __proto__
del objeto recién creado.

Si miramos la función constructora prototype
of Object
, se ve igual que la __proto__
of obj.
De hecho, son dos punteros que se refieren al mismo objeto.

obj.__proto__ === Object.prototype//true
Cada prototype
de una funcióntiene una propiedad inherente llamada constructor
que es un puntero a la función en sí. En el caso de la Object
función , el prototype
tieneconstructor
que apunta de nuevo a Object
.
Object.prototype.constructor === Object//true

En la imagen de arriba, el lado izquierdo es la vista ampliada del Object
constructor. Debes preguntarte cuáles son todas estas otras funciones sobre él. Bueno, las funciones son objetos , por lo que pueden tener propiedades sobre ellas como otros objetos.
Si miras de cerca, el Object
(a la izquierda) en sí tiene un__proto__
Lo que significa que Object
debe haber sido hecho de algún otro constructor que tiene un prototype.
AsObject
es un objeto de función, debe haber sido creado usando Function
constructor.

__proto__
de Object
se ve igual que prototype
de Function
. Cuando verifico la igualdad de ambos, resultan ser los mismos objetos.
Object.__proto__ === Function.prototype//true
Si miras de cerca, verás el Function
sí mismo tiene un __proto__
Lo que significa que Function
función constructoradebe haberse hecho a partir de alguna función constructora que tenga una extensión prototype
. ComoFunction
en sí es una función , debe haber sido hecha usandoFunction
constructor, es decir, a sí mismo. Sé que suena extraño, pero cuando lo revisas, resulta ser cierto.

los __proto__
de Function
yprototype
de Function
sonde hecho, dos punteros se refieren al mismo objeto.
Function.prototype === Function.__proto__\\true
Como se mencionó anteriormente, el constructor
de cualquierprototype
debe apuntar a la función que posee ese prototype.
los constructor
de prototype
de Function
apunta de nuevo a Function
sí mismo.
Function.prototype.constructor === Function\\true

De nuevo, el prototype
de Function
tiene un __proto__
Bueno, no es de extrañar ... prototype
es un objeto, puede tener uno. Pero observe también que apunta a laprototype
de Object
.
Function.prototype.__proto__ == Object.prototype\\true
Entonces podemos tener un mapa maestro aquí:

instanceof Operatora instanceof b
losinstanceof
el operador busca el objeto b
señalado porcualquiera de las constructor
(s) de encadenado__proto__
en a
. ¡Lee eso de nuevo! Si encuentra alguna referencia, regresatrue
otra cosa false
.
Ahora volvemos a nuestros primeros cuatro instanceof
declaraciones. He escrito declaraciones correspondientes que haceninstanceof
regreso true
para el siguiente:
Object instanceof FunctionObject.__proto__.constructor === Function
Object instanceof ObjectObject.__proto__.__proto__.constructor === Object
Function instanceof FunctionFunction.__proto__.constructor === Function
Function instanceof ObjectFunction.__proto__.__proto__.constructor === Object
¡¡Uf!! Incluso los espaguetis están menos enredados, pero espero que las cosas estén más claras ahora.
Aquí tengo algo que no señalé antes que prototype
deObject
no tiene un __proto__
.
En realidad tiene un __proto__
pero eso es igual a null
. La cadena tenía que terminar en algún lugar y termina aquí.
Object.prototype.__proto__\\null
Nuestra Object
, Function
,Object.prototype
yFunction.prototype
también tienen propiedades que son funciones, como Object.assign
,Object.prototype.hasOwnProperty
yFunction.prototype.call
. Estas son funciones internas que no tienen prototype
y también son instancias de Function
y tienen un__proto__
que es un puntero a Function.prototype
.

Object.create.__proto__ === Function.prototype\\true
Puede explorar otras funciones de constructor como Array
yDate
, o tomar sus objetos y buscar el prototype
y__proto__
. Estoy seguro de que podrás ver cómo está todo conectado.
Consultas adicionales:
Hay una pregunta más que me molestó durante un tiempo: ¿Por qué es que prototype
de Object
es objeto y prototype
de Function
es objeto de la función ?
aquíes una buena explicación si pensaras lo mismo.
Otra pregunta que podría ser un misterio para usted hasta ahora es: ¿Cómo obtienen los tipos de datos primitivos funciones como toString()
,substr()
y toFixed()
?Esto está bien explicado aquí .
Utilizando prototype
, podemos hacer que la herencia funcione con nuestros objetos personalizados en JavaScript. Pero ese es un tema para otro día.
¡Gracias por leer!