¿En qué se diferencia __proto__ de constructor.prototype?


163
function Gadget(name, color)
{
   this.name = name;
   this.color = color;
}

Gadget.prototype.rating = 3

var newtoy = new Gadget("webcam", "black")

newtoy.constructor.prototype.constructor.prototype.constructor.prototype 

Siempre devuelve el objeto con rating = 3.

Pero si hago lo siguiente:

newtoy.__proto__.__proto__.__proto__

La cadena termina volviendo null.

También en Internet Explorer, ¿cómo comprobaría el valor nulo si no hay una __proto__propiedad?


30
Este diagrama gráfico que le ayudará a entender la diferencia entre el prototipo y proto . Puede seguir la cadena de proto desde el objeto newtoy, y luego se dará cuenta de por qué el tercer Proto de newtoy es nulo.
bits

También está claro en el diagrama que newtoy.prototypeno es igual newtoy.constructor.prototypey, por newtoy.constructor.prototypelo tanto , no tendrá una propiedad llamada rating. Del mismo modo newtoy.constructor.prototype.constructor.propertytampoco tendrá propiedad llamada rating.
bits del

Error tipográfico en el último comentario: por newtoy.constructor.prototypelo tanto, tendrá una propiedad llamada calificación. Del mismo modo newtoy.constructor.prototype.constructor.propertytambién tendrá propiedad llamada calificación.
bits


1
@Royi Namir He subido jsViz en github. Aquí está el sitio de demostración . Por favor, no importa cuán descuidado (y sucio) esté el código real. Es un proyecto súper antiguo que no he tocado desde siempre.
bits

Respuestas:


210

He estado tratando de entender esto recientemente y finalmente se me ocurrió este "mapa" que creo que arroja luz sobre el asunto

http://i.stack.imgur.com/KFzI3.png ingrese la descripción de la imagen aquí

Sé que no soy el primero en inventar esto, pero fue más interesante descubrir que encontrarlo :-). De todos modos, después de eso encontré, por ejemplo, este otro diagrama que creo que dice básicamente lo mismo:

Diseño de objeto Javascript

Lo más sorprendente para mí fue descubrir que Object.__proto__apunta a Function.prototype, en lugar de Object.prototype, pero estoy seguro de que hay una buena razón para eso :-)

Pego el código mencionado en la imagen aquí también si alguien quiere probarlo. Tenga en cuenta que algunas propiedades se agregan a los objetos para facilitar saber dónde estamos después de algunos saltos:

Object.O1='';
Object.prototype.Op1='';

Function.F1 = '';
Function.prototype.Fp1 = '';

Cat = function(){};
Cat.C1 = '';
Cat.prototype.Cp1 = '';

mycat = new Cat();
o = {};

// EDITED: using console.dir now instead of console.log
console.dir(mycat);
console.dir(o);

2
@utsaina Muy guay. Verifique otra representación gráfica del código que OP publicó. Y creo que nuestros diagramas están de acuerdo en términos de detalles técnicos.
bits

43
La razón por la cual Object.__proto__apunta Function.prototypees porque Object()es una función nativa que crea una instancia de un objeto vacío. Por lo tanto, Object()es una función. Encontrará que todas las __proto__propiedades de los otros tipos nativos principales apuntan a Function.prototype. Object, Function, String, Number, Y Arraytodos heredamos el prototipo de función.
Giratorio

@drodsou tu segundo enlace es increíble. Compruébelo ahora, por favor;) mollypages.org/misc/js.mp Buena explicación: D
abhisekp

@Swivel "Por lo tanto, Object () es una función" - ¿Quiso decir que Object es una función? sin ()
giorgim

2
@GiorgiMoniava Correcto. Objecten sí mismo es una función; El resultado de ejecutar invocables Object(es decir, el valor de retorno de la ejecución Object()) no es una función.
Giratorio

67

constructores una propiedad [[DontEnum]] predefinida del objeto señalado por la prototypepropiedad de un objeto de función e inicialmente apuntará al objeto de función en sí.

__proto__ es equivalente a la propiedad interna [[Prototype]] de un objeto, es decir, su prototipo real.

Cuando crea un objeto con el newoperador, su propiedad interna [[Prototype]] se establecerá en el objeto señalado por la función del constructorprototype propiedad de .

Esto significa que .constructorse evaluará .__proto__.constructor, es decir, la función constructora utilizada para crear el objeto, y como hemos aprendido, la protoypepropiedad de esta función se utilizó para establecer el [[Prototipo]] del objeto.

Se deduce que .constructor.prototype.constructores idéntico a .constructor(siempre y cuando estas propiedades no se hayan sobrescrito); Vea aquí para una explicación más detallada.

Si __proto__está disponible, puede recorrer la cadena de prototipos real del objeto. No hay forma de hacer esto en ECMAScript3 simple porque JavaScript no fue diseñado para jerarquías de herencia profunda.


3
Ese enlace 'aquí' es el estándar de oro. Ve allí si quieres la descripción completa.
Ricalsin

Buena captura con .constructor.prototypeencadenamiento. Tampoco estaba claro para mí, aunque no vi que eso .constructores igual .__proto__.constructor. Lo que simplemente significa alternar entre la función del constructor y su prototipo.
Johnny_D

30

La herencia prototípica en JavaScript se basa en la __proto__propiedad en el sentido de que cada objeto hereda el contenido del objeto al que hace referencia su__proto__ propiedad.

La prototypepropiedad es especial solo para Functionobjetos y solo cuando se utiliza el newoperador para llamar a un Functionconstructor. En este caso, los objetos creados __proto__se establecerán en constructores Function.prototype.

Esto significa que agregar a Function.prototypese reflejará automáticamente en todos los objetos a los que __proto__se hace referencia Function.prototype.

Reemplazar el constructor Function.prototypecon otro objeto no actualizará la __proto__propiedad de ninguno de los objetos ya existentes.

Tenga en cuenta que __proto__no se debe acceder directamente a la propiedad, sino que se debe usar Object.getPrototypeOf (objeto) .

Para responder a la primera pregunta, he creado un diagrama __proto__y prototypereferencias a medida , desafortunadamente stackoverflow no me permite agregar la imagen con "menos de 10 reputación". Quizás en otra ocasión.

[Editar] La figura usa en [[Prototype]]lugar de __proto__porque así es como la especificación ECMAScript se refiere a objetos internos. Espero que puedas resolverlo todo.

Aquí hay algunos consejos para ayudarlo a comprender la figura:

red    = JavaScript Function constructor and its prototype
violet = JavaScript Object constructor and its prototype
green  = user-created objects
         (first created using Object constructor or object literal {},
          second using user-defined constructor function)
blue   = user-defined function and its prototype
         (when you create a function, two objects are created in memory:
          the function and its prototype)

Tenga en cuenta que la constructorpropiedad no existe en los objetos creados, sino que se hereda del prototipo.

ingrese la descripción de la imagen aquí


@xorcus ¿Puede explicar esto: new MyFunction()crea una instancia de objeto que __proto__debería referirse a su prototipo ctor que es MyFunction.prototype.Entonces, ¿por qué se MyFunction.prototype.__proto__refiere Object.prototype? debería referirse (como mi primera muestra) al prototipo de su ctor que es MyFunction.prototype(note que MyFunction.prototypees un instinto de Myfunction)
Royi Namir

@Royi Namir: MyFunction.prototype .__ proto__ se refiere a Object.prototype porque MyFunction.prototype es un objeto. Object.prototype es heredado por todos los objetos (normalmente, ahí es donde termina la cadena de herencia del prototipo). No estoy de acuerdo con que MyFunction.prototype sea una instancia de MyFunction. obj instanceof MyFunction <=> MyFunction.prototype.isPrototypeOf (obj) <=> MyFunction.prototype existe en la cadena de prototipos obj. Ese no es el caso del objeto
MyFunction.prototype

14

Objectes Eva, y Functiones Adán, Adán ( Function) usa su hueso ( Function.prototype) para crear Eva ( Object). Entonces, ¿quién creó a Adam ( Function)? - El inventor del lenguaje JavaScript :-).

Según la respuesta de utsaina, quiero agregar más información útil.

Lo más sorprendente para mí fue descubrir que Object.__proto__ apunta a Function.prototype, en lugar de Object.prototype, pero estoy seguro de que hay una buena razón para eso :-)

NO debería ser. Object.__proto__NO debería señalar Object.prototype. En cambio, la instancia de Object o, o.__proto__debería apuntar aObject.prototype .

(Perdóname por usar los términos classyinstance en JavaScript, pero lo sabes :-)

Creo que la clase en Objectsí es una instancia de Function, por eso Object.__proto__ === Function.prototype. Por lo tanto: Objectes Eva, y Functiones Adán, Adán ( Function) usa su hueso ( Function.prototype) para crear Eva (Object ).

Además, incluso la clase Functionmisma es una instancia de Functionsí misma, es Function.__proto__ === Function.prototypedecir, también es por esoFunction === Function.constructor

Además, la clase regular Cates una instancia de Function, es decir Cat.__proto__ === Function.prototype.

La razón de lo anterior es, cuando creamos una clase en JavaScript, en realidad, solo estamos creando una función, que debería ser una instancia de Function. Objecty Functionson simplemente especiales, pero siguen siendo clases, mientras que Cates una clase regular.

Como cuestión de factor, en el motor JavaScript de Google Chrome, los siguientes 4:

  • Function.prototype
  • Function.__proto__
  • Object.__proto__
  • Cat.__proto__

Todos son ===(absolutamente iguales) a los otros 3, y su valor esfunction Empty() {}

> Function.prototype
  function Empty() {}
> Function.__proto__
  function Empty() {}
> Object.__proto__
  function Empty() {}
> Cat.__proto__
  function Empty() {}
> Function.prototype === Function.__proto__
  true
> Function.__proto__ === Object.__proto__
  true
> Object.__proto__ === Cat.__proto__
  true

OKAY. Entonces, ¿quién crea el especial function Empty() {}( Function.prototype)? Piénsalo :-)


De acuerdo con eso, excepto por la última cosa: ¿a qué se function Empty() {}refiere como igual a Function.prototype, etc. ?, ¿cuál es el código que usó en la consola de Chrome?
drodsou

2
Corregí la última cosa que usted señaló. Su valor está function Empty() {}en Google Chrome. También agregué la salida de la consola.
Peter Lee

todas las funciones son instancia de Function y, por lo tanto, todas las funciones heredan ( _ _proto_ _) de Function.prototype. Es tan simple como eso :)
xorcus

Perdón por comentar sobre el viejo hilo. ¿Pero son creados por Inventor of Language?
Patel Parth

6

Realmente no sé por qué la gente no te corrigió sobre dónde está el problema real en tu comprensión.

Esto facilitaría mucho la detección del problema.

Así que veamos qué está pasando:

var newtoy = new Gadget("webcam", "black")

newtoy 
  .constructor //newtoy's constructor function is newtoy ( the function itself)
    .prototype // the function has a prototype property.( all functions has)
      .constructor // constructor here is a **property** (why ? becuase you just did `prototype.constructor`... see the dot ? )  ! it is not(!) the constructor function  !!! this is where your mess begins. it points back to the constructor function itself ( newtoy function)
         .prototype // so again we are at line 3 of this code snippet
            .constructor //same as line 4 ...
                .prototype 
                 rating = 3

Genial, ahora veamos esto __proto__

Antes de eso, recuerde 2 cosas con respecto a __proto__ :

  1. Cuando crea un objeto con el newoperador, su propiedad [[Prototype]]/ interno proto__se establecerá en la prototypepropiedad (1) de su constructor functiono "creador" si lo desea.

  2. Codificado dentro de JS -: Object.prototype.__proto__es null.

Vamos a referirnos a estos 2 puntos como " bill"

newtoy
     .__proto__ // When `newtoy` was created , Js put __proto__'s value equal to the value of the cunstructor's prototype value. which is `Gadget.prototype`.
       .__proto__ // Ok so now our starting point is `Gadget.prototype`. so  regarding "bill" who is the constructor function now? watch out !! it's a simple object ! a regular object ! prototype is a regular object!! so who is the constructor function of that object ? Right , it's the `function Object(){...}`.  Ok .( continuing "bill" ) does it has a `prototype` property ? sure. all function has. it's `Object.prototype`. just remember that when Gadget.prototype was created , it's internal `__proto__` was refered to `Object.prototype` becuase as "bill" says :"..will be set to the `prototype` property of   its `constructor function`"
          .__proto__ // Ok so now our satrting point is `Object.prototype`. STOP. read bullet 2.Object.prototype.__proto__ is null by definition. when Object.prototype ( as an object) was created , they SET THE __PROTO__ AS NULL HARDCODED

¿Mejor?


2

Cada función crea su prototipo. Y cuando creamos un objeto usando el constructor de esa función, la propiedad __proto__ de mi objeto comenzará a apuntar al prototipo de esa función.


1
Creo que querías decir la __proto__propiedad.
retiro el

Si. Me refería a la propiedad proto de un objeto. Espero que haya sido útil la información.
Apoorv Nag

2

Si todas esas cifras fueran abrumadoras, echemos un vistazo a lo que significan las propiedades.

STH.prototype

Al crear una nueva función, se crea un objeto vacío en paralelo y se vincula a la función con la [[Prototype]]cadena. Para acceder a este objeto, utilizamos la prototypepropiedad de la función.

function Gadget() {}
// in background, new object has been created
// we can access it with Gadget.prototype
// it looks somewhat like {constructor: Gadget}

Tenga en cuenta que la prototypepropiedad solo está disponible para funciones.

STH.constructor

El objeto prototipo mencionado anteriormente no tiene propiedades excepto uno - constructor. Esta propiedad representa una función que creó el objeto prototipo.

var toy = new Gadget();

Al crear la Gadgetfunción, también creamos un objeto {constructor: Gadget}, que no se parece en nada Gadget.prototype. Como se constructorrefiere a una función que creó un prototipo de objeto, toy.constructorrepresenta la Gadgetfunción. Escribimos toy.constructor.prototypey estamos recibiendo{constructor: Gadget} volviendo a .

Por lo tanto, hay un círculo vicioso: puedes usarlo toy.constructor.prototype.constructor.prototype.constructor.prototype.constructor.prototype.constructor.prototype.constructor.prototype.constructor.prototype.constructor.prototypey siempre lo será Gadget.prototype.

toy
.constructor    // Gadget
.prototype    // {constructor: Gadget}
.constructor    // Gadget
.prototype    // {constructor: Gadget}
// ...

STH .__ proto__

Mientras que prototypees una propiedad específica para funciones, __proto__está disponible para todos los objetos tal como se establece Object.prototype. Se refiere al prototipo de una función que puede crear un objeto.

[].__proto__ === Array.prototype
// true

({}).__proto === Object.prototype
// true

Aquí toy.__proto__está Gadget.prototype. Como Gadget.prototypees un objeto ( {}) y los objetos se crean con la Objectfunción (ver el ejemplo anterior), obtenemos Object.prototype. Este es el objeto más alto en JavaScript y __proto__solo puede indicarlo null.

toy
.__proto__    // Gadget.prototype (object looking like {constructor: Gadget})
.__proto__    // Object.prototype (topmost object in JS)
.__proto__    // null - Object.prototype is the end of any chain

0

Respuesta corta: __proto__es una referencia a la prototypepropiedad del constructor que creó el objeto.

Objetos en JavaScript

Un objeto JavaScript es un tipo integrado para una colección de cero o más propiedades. Las propiedades son contenedores que contienen otros objetos, valores primitivos o funciones.

Constructores en JavaScript

Las funciones son objetos regulares (que se implementan [[Call]]en términos de ECMA-262) con la capacidad adicional de ser invocables pero juegan otro papel en JavaScript: se convierten en constructores ( fábricas para objetos) si se invocan a través denew operador. Los constructores son, pues, un análogo aproximado de las clases en otros idiomas.

Cada función de JavaScript es en realidad una instancia del Functionobjeto de función incorporado que tiene una propiedad especial llamada prototypeutilizada para implementar la herencia basada en prototipos y las propiedades compartidas. Cada objeto creado por una función constructora tiene una referencia implícita (llamada prototipo o __proto__) al valor de su constructor prototype.

El constructor prototypees una especie de plano para construir objetos, ya que cada objeto creado por el constructor hereda una referencia a suprototype .

La cadena prototipo

Un objeto especifica su prototipo mediante la propiedad interna [[Prototype]]o __proto__. La relación prototipo entre dos objetos es sobre herencia: cada objeto puede tener otro objeto como prototipo. El prototipo puede ser el nullvalor.

La cadena de objetos conectados por la __proto__propiedad se llama cadena prototipo. . Cuando se hace una referencia a una propiedad en un objeto, esa referencia es a la propiedad encontrada en el primer objeto en la cadena de prototipo que contiene una propiedad de ese nombre. La cadena prototipo se comporta como si fuera un solo objeto.

Ver esta imagen (extraída de este blog ):

proto.jpg

Cada vez que intenta acceder a una propiedad en un objeto, JavaScript comienza la búsqueda de ese objeto y continúa con su prototipo, el prototipo del prototipo y así sucesivamente hasta que se encuentra la propiedad o si __proto__contiene el valor null.

Este tipo de herencia que usa la cadena de prototipos a menudo se llama delegación para evitar confusión con otros idiomas que usan la cadena de clase.

Casi todos los objetos son instancias de Object, porque Object.prototypees el último en su cadena de prototipos. Pero Object.prototypeno es una instancia de Objectporque Object.prototype.__proto__tiene el valor null.

También puede crear un objeto con un nullprototipo como este:

var dict = Object.create(null);

Este tipo de objeto es un mejor mapa (diccionario) de un objeto literal, por lo que este patrón es a veces llamado el dict patrón ( dict para el diccionario).

Nota: los objetos literales creados usando {}son instancias de Objectya que ({}).__proto__es una referencia a Object.prototype.


Cite la fuente de las citas y artefactos que está utilizando. La imagen parece provenir de giamir.com/pseudoclasses-and-prototypal-inheritance-in-JS , ¿tiene derechos de autor sobre ella?
Bergi

@ Bergi Cité la fuente de la imagen. La mayoría de las citas que utilicé se extraen del estándar JS o del MDN
eigenslacker
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.