__proto__ VS. prototipo en JavaScript

785

Esta figura muestra nuevamente que cada objeto tiene un prototipo. La función de constructor Foo también tiene su propia __proto__función, Function.prototype, y que a su vez también hace referencia a través de su __proto__propiedad al Object.prototype. Por lo tanto, repita, Foo.prototype es solo una propiedad explícita de Foo que se refiere al prototipo de los objetos byc.

var b = new Foo(20);
var c = new Foo(30);

¿Cuáles son las diferencias entre __proto__y prototype?

enter image description here

La cifra fue tomada de dmitrysoshnikov.com .

0x90
fuente
55
Creo que de arriba hacia abajo o de abajo hacia arriba es una cuestión de preferencia. De hecho, lo prefiero de esta manera, así puedo rastrear el diagrama hasta encontrar de dónde viene algo.
Mike Lippert
1
Me gusta cómo JavaScript usa la herencia prototípica para resolver y.constructor a y .__ proto __. Constructor. También me gusta cómo Object.prototype se encuentra en la parte superior de la cadena de herencia prototípica con Object.prototype .__ proto__ establecido en nulo. También me gusta cómo el diagrama hace una visualización conceptual de tres columnas de cómo el programador piensa en los objetos como 1. instancias, 2. constructores, 3. prototipos que los constructores asocian con esas instancias cuando se instancia a través de la nueva palabra clave.
John Sonderson
El diagrama tiene sentido inmediatamente después de ver algo como youtube.com/watch?v=_JJgSbuj5VI , por cierto
mlvljr
Y ahora, como he leído las respuestas, me siento obligado a recomendar realmente el video anterior, ya que de hecho tiene una explicación cristalina (y no WTFy) de lo que está sucediendo :)
mlvljr

Respuestas:

766

__proto__es el objeto real que se usa en la cadena de búsqueda para resolver métodos, etc. prototypees el objeto que se usa para construir __proto__cuando crea un objeto con new:

( new Foo ).__proto__ === Foo.prototype;
( new Foo ).prototype === undefined;
Mark Kahn
fuente
239
Ah! Por prototypelo tanto, no está disponible en las propias instancias (u otros objetos), sino solo en las funciones de constructor.
rvighne
43
@rvighne: prototypesólo está disponible en las funciones ya que se derivan de Function, Functiony Objectsino en cualquier otra cosa que no es. Sin embargo, __proto__está disponible en todas partes.
Tarik
19
También lo __proto__es el objeto real que se guarda y se usa como prototipo, mientras que Myconstructure.prototypees solo un modelo para el __proto__cual, de hecho, se guarda el objeto real y se usa como el prototipo. Por lo tanto, myobject.prototypeno sería una propiedad del objeto real porque es solo una cosa temporal utilizada por la función de constructor para describir cómo myobject.__proto__debería ser.
Alex_Nabu
99
¿Es justo decir que la __proto__propiedad de un objeto es un puntero a la prototypepropiedad de la función constructora del objeto ? es decir, foo .__ proto__ === foo.constructor.prototype
Niko Bellic
10
@Alex_Nabu No del todo. newCar.__proto__ IS Car.prototype , no una instancia de Car.prototype. Mientras Car.protoype ES una instancia de un object. Car.prototypeno es algo que otorgue newCarpropiedades o estructura, simplemente ES el próximoobject en newCarla cadena de prototipos. Car.prototypeNo es temporal object. Es el objectque se establece como el valor de la __proto__propiedad de cualquier nuevo objects hecho usando Carcomo constructor. Si quiere pensar en algo como un plano object, piense Caren un plano para automóviles nuevos object.
seangwright
336

prototypees una propiedad de un objeto Function. Es el prototipo de objetos construidos por esa función.

__proto__es propiedad interna de un objeto, apuntando a su prototipo. Los estándares actuales proporcionan un Object.getPrototypeOf(O)método equivalente , aunque el estándar de facto __proto__es más rápido.

Puede encontrar instanceofrelaciones comparando una función prototypecon la __proto__cadena de un objeto , y puede romper estas relaciones cambiando prototype.

function Point(x, y) {
    this.x = x;
    this.y = y;
}

var myPoint = new Point();

// the following are all true
myPoint.__proto__ == Point.prototype
myPoint.__proto__.__proto__ == Object.prototype
myPoint instanceof Point;
myPoint instanceof Object;

Aquí Pointhay una función constructora, construye un objeto (estructura de datos) procesalmente. myPointes un objeto construido por Point()lo que Point.prototypese guarda myPoint.__proto__en ese momento.

Diablillo
fuente
2
Además, si cambia la __proto__propiedad de un objeto, cambia el objeto en el que se realizan las búsquedas de prototipos. Por ejemplo, puede agregar un objeto de métodos como una función __proto__para tener una especie de objeto de instancia invocable.
kzh
myPoint .__ proto __. constructor.prototype == Point.prototype
Francisco
@kzh lol que me dio un resultado divertido console.log(obj1.call) // [Function: call] obj1.call()// TypeError: obj1.call no es una función. Lo hiceobj.__proto__ = Function.__proto__
abhisekp 01 de
myFn.__proto__ = {foo: 'bar'}
kzh
Creo que tengo tu punto.
ComicScrip
120

La propiedad prototipo se crea cuando se declara una función.

Por ejemplo:

 function Person(dob){
    this.dob = dob
 }; 

Person.prototypeLa propiedad se crea internamente una vez que declara la función anterior. Se pueden agregar muchas propiedades al Person.prototype que comparten las instancias de Person creadas con la nueva Person ().

// adds a new method age to the Person.prototype Object.
Person.prototype.age = function(){return date-dob}; 

Vale la pena señalar que Person.prototypees unObject literal por defecto (se puede cambiar según sea necesario).

Cada instancia creada usando new Person()tiene una __proto__propiedad que apunta a Person.prototype. Esta es la cadena que se usa para atravesar para encontrar una propiedad de un objeto en particular.

var person1 = new Person(somedate);
var person2 = new Person(somedate);

crea 2 instancias de Person, estos 2 objetos pueden llamar al agemétodo de Person.prototypecomoperson1.age , person2.age.

En la imagen de arriba de su pregunta, puede ver que Fooes un Function Objecty, por lo tanto, tiene un __proto__enlace al Function.prototypeque a su vez es una instancia Objecty tiene un __proto__enlace Object.prototype. El enlace de proto termina aquí con __proto__enObject.prototype apuntando a null.

Cualquier objeto puede tener acceso a todas las propiedades en su cadena de proto como unidas __proto__, formando así la base para la herencia prototípica.

__proto__ no es una forma estándar de acceder a la cadena de prototipos, el enfoque estándar pero similar es usar Object.getPrototypeOf(obj) .

El siguiente código para el instanceofoperador ofrece una mejor comprensión:

instanceofEl operador de clase de objeto regresa truecuando un objeto es una instancia de una clase, más específicamente si Class.prototypese encuentra en la cadena de protocolo de ese objeto, entonces el objeto es una instancia de esa clase.

function instanceOf(Func){
  var obj = this;
  while(obj !== null){
    if(Object.getPrototypeOf(obj) === Func.prototype)
      return true;
    obj = Object.getPrototypeOf(obj);
  }
  return false;
}      

El método anterior se puede llamar como: instanceOf.call(object, Class)que devuelve verdadero si el objeto es una instancia de Clase.

sid_k_reddy
fuente
2
Me preguntaba por qué el prototypeobjeto fue creado internamente en primer lugar. ¿Podría uno simplemente asignar métodos estáticos al objeto de función en sí? por ejemplo function f(a){this.a = a}; f.increment = function(){return ++this.a}? ¿Por qué no se eligió esta forma en lugar de agregar los métodos al prototypeobjeto? Esto funcionará si f.__proto__ = gdonde g es la clase base.
abhisekp 01 de
Tal vez el prototypeobjeto se eligió para compartir porque solo las propiedades exclusivas del constructor de funciones se pueden almacenar en el objeto constructor de funciones.
abhisekp 01 de
1
En realidad, eso sería un desastre porque instanceofdaría como resultado ({}) instanceof Function === trueque no habría forma de diferenciar entre prototipos si prototypese elimina la propiedad.
abhisekp 01 de
@abhisekp ¿Qué quiere decir con esto: "Esto funcionará si f .__ proto__ = g donde g es la clase base". No sé si esto tiene algún significado que no entiendo, pero si tuviera que agregar las propiedades y los métodos de esa manera, cuando usara la newpalabra clave para crear una instancia, las propiedades y los métodos no se copiarían terminado.
doubleOrt
67

Una buena manera de pensarlo es ...

prototypeEs utilizado por las constructor()funciones. Realmente debería haberse llamado algo así como,"prototypeToInstall" , ya que eso es lo que es.

y __proto__es ese "prototipo instalado" en un objeto (que fue creado / instalado sobre el objeto desde dicha constructor()función)

sarink
fuente
2
Lo voté a favor, pero tal vez la razón del voto negativo se debió a que la declaración "el prototipo es utilizado por las funciones constructor ()" puede sonar como si las funciones no constructoras no lo tuvieran, lo cual no es el caso, sin embargo, además de eso, ahora no es nuestro enfoque también se puede notar que cada función es potencialmente un constructor si se llama con new ...
yoel halb
2
Cambie " constructor()funciones" a "funciones de constructor", ya que puede haber confusión con " __proto__.constructor()funciones". Considero esto importante, ya que el constructor __proto __. No se invoca realmente cuando newse usa una palabra clave.
Alexander Gonchiy
1
La afirmación de que "el prototipo es usado por las funciones constructor () " solo cuenta una parte de un hecho importante, pero lo dijo de una manera que probablemente lleve a los lectores a pensar que es todo el hecho. el prototipo se crea internamente para cada declaración de función en Javascript, independientemente de cómo se llamará esa función en el futuro, con o sin la nueva palabra clave; El prototipo de una función declarada apunta a un objeto literal.
Yiling
62

Para explicar, creemos una función

 function a (name) {
  this.name = name;
 }

Cuando JavaScript ejecuta este código, agrega prototypepropiedad a a, la prototypepropiedad es un objeto con dos propiedades:

  1. constructor
  2. __proto__

Entonces cuando lo hacemos

a.prototype vuelve

     constructor: a  // function definition
    __proto__: Object

Ahora, como puede ver, constructorno es más que la función en así y __proto__apunta al nivel raízObject de JavaScript.

Veamos qué sucede cuando usamos la afunción con la newpalabra clave.

var b = new a ('JavaScript');

Cuando JavaScript ejecuta este código, hace 4 cosas:

  1. Crea un nuevo objeto, un objeto vacío // {}
  2. Se crea __proto__en by hace que apunte a a.prototypepor lob.__proto__ === a.prototype
  3. Se ejecuta a.prototype.constructor(que es la definición de función a) con el objeto recién creado (creado en el paso 1) como contexto (esto), por lo tanto, la namepropiedad se pasa como 'JavaScript' (que se agrega athis ) se agrega al objeto recién creado.
  4. Devuelve el objeto recién creado en (creado en el paso 1) para que var bse asigne al objeto recién creado.

Ahora si agregamos a.prototype.car = "BMW"y hacemos b.car , aparece la salida "BMW".

Esto se debe a que cuando JavaScript ejecutó este código en el que buscó la carpropiedad b, no encontró el JavaScript utilizado b.__proto__(que se hizo para apuntar a 'a.prototype' en el paso 2) y encuentra la carpropiedad, así que devuelve "BMW".

Manishz90
fuente
2
1. constructorno vuelve a()! Vuelve a. 2. __proto__devuelve Object.prototype, no el objeto raíz en Javascript.
doubleOrt
1
¡Esta es una respuesta genial!
john-raymon
+1 esta es la mejor respuesta para explicar qué prototipo es realmente (un objeto con dos propiedades) y cómo Javascript ejecuta cada fragmento de código. Esta información es sorprendentemente difícil de encontrar.
java-addict301
53

Prototipo VS. __proto__ VS. [[Prototipo]]

Al crear una función, se crea automáticamente un objeto de propiedad llamado prototipo (no lo creó usted mismo) y se adjunta al objeto de función (el constructor).
Nota : Este nuevo objeto prototipo también apunta o tiene un enlace privado interno al Objeto JavaScript nativo.

Ejemplo:

function Foo () {
    this.name = 'John Doe';
}

// Foo has an object property called prototype.
// prototype was created automatically when we declared the function Foo.
Foo.hasOwnProperty('prototype'); // true

// Now, we can assign properties and methods to it:
Foo.prototype.myName = function () {
    return 'My name is ' + this.name;
}

Si crea un nuevo objeto al Foousar la newpalabra clave, básicamente está creando (entre otras cosas) un nuevo objeto que tiene un enlace interno o privado al Fooprototipo de la función que discutimos anteriormente:

var b = new Foo();

b.[[Prototype]] === Foo.prototype  // true


El enlace privado al objeto de esa función se llama prototipo de doble paréntesis o simplemente [[Prototype]]. Muchos navegadores nos proporcionan un enlace público que llama__proto__ !

Para ser más específicos, en __proto__realidad es una función getter que pertenece al objeto JavaScript nativo. Devuelve el enlace prototipo interno-privado de lo que sea el thisenlace (devuelve el [[Prototype]]de b):

b.__proto__ === Foo.prototype // true

Vale la pena señalar que, al comenzar ECMAScript5, también puede usar el método getPrototypeOf para obtener el enlace privado interno:

Object.getPrototypeOf(b) === b.__proto__ // true


NOTA: esta respuesta no tiene la intención de abarcar todo el proceso de creación de nuevos objetos o nuevos constructores, sino para ayudar a comprender mejor lo que es __proto__, prototypey [[Prototype]]y cómo funciona.

Lior Elrom
fuente
2
@Taurus, haga clic en el encabezado, conduce al documento de especificaciones ECMAScript. Consulte la sección 9 (Comportamientos de objetos ordinarios y exóticos) que lo explican con mucho más detalle.
Lior Elrom
Creo que hay un error aquí: _ un nuevo objeto que tiene un enlace interno o privado al prototipo de la función Foo_ ¿Quiere decir: un nuevo objeto que tiene un enlace interno o privado al prototipo de la función Foo ?
Koray Tugay
1
Gracias @ KorayTugay! Sí, lo
escribí
31

Para dejarlo un poco claro, además de las excelentes respuestas anteriores:

function Person(name){
    this.name = name
 }; 

var eve = new Person("Eve");

eve.__proto__ == Person.prototype //true

eve.prototype  //undefined

Las instancias tienen __proto__ , las clases tienen prototipo .

serkan
fuente
12

En JavaScript, una función se puede utilizar como constructor. Eso significa que podemos crear objetos a partir de ellos utilizando la nueva palabra clave. Cada función de constructor viene con un objeto incorporado encadenado con ellos. Este objeto incorporado se llama prototipo.Instances of a constructor function use __proto__ to access the prototype property of its constructor function.

diagrama prototipo

  1. Primero creamos un constructor: function Foo(){}. Para ser claros, Foo es solo otra función. Pero podemos crear un objeto a partir de él con la nueva palabra clave. Por eso lo llamamos la función constructora.

  2. Cada función tiene una propiedad única que se llama propiedad prototipo. Entonces, la función ConstructorFoo tiene una propiedad prototipo que apunta a su prototipo, que es Foo.prototype(ver imagen).

  3. Las funciones de constructor son en sí mismas una función que es una instancia de un constructor de sistema llamado constructor [[Función]]. Entonces podemos decir que function Fooestá construido por un constructor [[Función]]. Entonces, __proto__de nuestro Foo functionapuntará al prototipo de su constructor, que esFunction.prototype .

  4. Function.prototypees en sí mismo nada más que un objeto que se construye a partir de otro constructor de sistema llamado [[Object]]. Entonces, [[Object]]es el constructor de Function.prototype. Entonces, podemos decir que Function.prototypees una instancia de [[Object]]. Así __proto__de Function.prototypepuntos a Object.prototype.

  5. Object.prototypees el último hombre en la cadena de prototipos. Quiero decir que no ha sido construido. Ya está allí en el sistema. Entonces sus __proto__puntos a null.

  6. Ahora llegamos a instancias de Foo. Cuando creamos una instancia usando new Foo(), crea un nuevo objeto que es una instancia de Foo. Eso significa que Fooes el constructor de estas instancias. Aquí creamos dos instancias (x e y). __proto__de x e y por lo tanto apunta a Foo.prototype.

AL-zami
fuente
Para ser claros: ¿las instancias no tienen la propiedad .prototype? Solo la función constructora ¿verdad? ... Entonces, la diferencia entre una instancia y su función de constructor es: las funciones de constructor tienen ambos 1. proto 2. .prototipo, mientras que las instancias solo tienen la propiedad .__ proto__ ... ¿correcto?
Shaz
@ Shaz tienes razón. Las instancias utilizan su protocolo para acceder a la propiedad prototipo de su función de constructor.
AL-zami
Pero, ¿por qué cuando escribes: var car = Object.create (Vehicle); obtendrás car .__ proto__ = Vehicle PERO también obtienes una propiedad car.prototype que apunta a Vehicle.prototype?
Shaz
@shaz, ¿puede proporcionar un jsfiddle para que pueda visualizar la situación?
AL-zami
1
aquí car.prototype es una propiedad heredada. El coche hereda la propiedad 'prototipo' de la función del vehículo. entonces car.prototype === vehicle.prototype. La propiedad "prototipo" es una propiedad del vehículo. El automóvil puede acceder a él a través de su prototipo de cadena. Espero que esto despejar su confusión
AL-zami
8

Resumen:

La __proto__propiedad de un objeto es una propiedad que se asigna a la prototypefunción constructora del objeto. En otras palabras:

instance.__proto__ === constructor.prototype // true

Esto se usa para formar la prototypecadena de un objeto. La prototypecadena es un mecanismo de búsqueda de propiedades en un objeto. Si se accede a la propiedad de un objeto, JavaScript primero buscará en el objeto mismo. Si la propiedad no se encuentra allí, subirá hastaprotochain hasta que se encuentre (o no)

Ejemplo:

function Person (name, city) {
  this.name = name;
}

Person.prototype.age = 25;

const willem = new Person('Willem');

console.log(willem.__proto__ === Person.prototype); // the __proto__ property on the instance refers to the prototype of the constructor

console.log(willem.age); // 25 doesn't find it at willem object but is present at prototype
console.log(willem.__proto__.age); // now we are directly accessing the prototype of the Person function 

Nuestros primeros resultados de registro trueson, porque como se mencionó, la __proto__propiedad de la instancia creada por el constructor se refiere aprototype propiedad del constructor. Recuerde, en JavaScript, las funciones también son objetos. Los objetos pueden tener propiedades, y una propiedad predeterminada de cualquier función es una propiedad llamada prototipo.

Entonces, cuando esta función se utiliza como una función constructora, el objeto instanciado de ella recibirá una propiedad llamada __proto__. Y esta __proto__propiedad se refiere a la prototypepropiedad de la función constructora (que por defecto tiene cada función).

¿Por qué es útil esto?

JavaScript tiene un mecanismo al buscar propiedades en el Objectsque se llama 'herencia prototípica' , esto es lo que básicamente hace:

  • Primero, se verifica si la propiedad se encuentra en el Objeto mismo. Si es así, se devuelve esta propiedad.
  • Si la propiedad no se encuentra en el objeto en sí, 'trepará por la protochain'. Básicamente mira el objeto al que hace referencia la __proto__propiedad. Allí, comprueba si la propiedad está disponible en el objeto al que hace referencia __proto__.
  • Si la propiedad no se encuentra en el __proto__objeto, trepará por la __proto__cadena hasta el Objectobjeto.
  • Si no puede encontrar la propiedad en ningún lugar del objeto y su prototypecadena, volverá undefined.

Por ejemplo:

function Person (name) {
  this.name = name;
}

let mySelf = new Person('Willem');

console.log(mySelf.__proto__ === Person.prototype);

console.log(mySelf.__proto__.__proto__ === Object.prototype);

Willem van der Veen
fuente
7

Estoy aprendiendo el prototipo de You Don't Know JS: this & Object Prototypes , que es un libro maravilloso para comprender el diseño debajo y aclarar tantas ideas falsas (es por eso que estoy tratando de evitar el uso de la herencia y cosas por el estilo instanceof).

Pero tengo la misma pregunta que la gente hizo aquí. Varias respuestas son realmente útiles y esclarecedoras. También me encantaría compartir mis entendimientos.


¿Qué es un prototipo?

Los objetos en JavaScript tienen una propiedad interna, indicada en la especificación como [[Prototype]], que es simplemente una referencia a otro objeto. Casi todos los objetos reciben un nonull valor para esta propiedad, en el momento de su creación.

¿Cómo obtener el prototipo de un objeto?

a través de __proto__oObject.getPrototypeOf

var a = { name: "wendi" };
a.__proto__ === Object.prototype // true
Object.getPrototypeOf(a) === Object.prototype // true

function Foo() {};
var b = new Foo();
b.__proto__ === Foo.prototype
b.__proto__.__proto__ === Object.prototype

¿Cuál es el prototype?

prototypees un objeto creado automáticamente como una propiedad especial de una función , que se utiliza para establecer la cadena de delegación (herencia), también conocida como cadena de prototipo.

Cuando creamos una función a, prototypese crea automáticamente como una propiedad especial sobre ay guarda el código de función en la que el constructorsobre prototype.

function Foo() {};
Foo.prototype // Object {constructor: function}
Foo.prototype.constructor === Foo // true

Me encantaría considerar esta propiedad como el lugar para almacenar las propiedades (incluidos los métodos) de un objeto de función. Esa es también la razón por funciones de utilidad en JS se definen como Array.prototype.forEach(), Function.prototype.bind(),Object.prototype.toString().

¿Por qué enfatizar la propiedad de una función ?

{}.prototype // undefined;
(function(){}).prototype // Object {constructor: function}

// The example above shows object does not have the prototype property.
// But we have Object.prototype, which implies an interesting fact that
typeof Object === "function"
var obj = new Object();

Así, Arary, Function, Objectson todas las funciones. Debo admitir que esto refresca mi impresión sobre JS. Sé que las funciones son ciudadanos de primera clase en JS, pero parece que se basa en funciones.

¿Cuál es la diferencia entre __proto__y prototype?

__proto__una referencia funciona en cada objeto para referirse a su [[Prototype]]propiedad.

prototypees un objeto creado automáticamente como una propiedad especial de una función , que se utiliza para almacenar las propiedades (incluidos los métodos) de un objeto de función.

Con estos dos, podríamos mapear mentalmente la cadena de prototipos. Como esta imagen ilustra:

function Foo() {}
var b = new Foo();

b.__proto__ === Foo.prototype // true
Foo.__proto__ === Function.prototype // true
Function.prototype.__proto__ === Object.prototype // true
ifyouseewendy
fuente
7

 Prototipo de JavaScript vs __prototipo__

'use strict'
function A() {}
var a = new A();
class B extends A {}
var b = new B();
console.log('====='); // =====
console.log(B.__proto__ === A); // true
console.log(B.prototype.__proto__ === A.prototype); // true
console.log(b.__proto__ === B.prototype); // true
console.log(a.__proto__ === A.prototype); // true
console.log(A.__proto__ === Function.__proto__); // true
console.log(Object.__proto__ === Function.__proto__); // true
console.log(Object.prototype === Function.__proto__.__proto__); // true
console.log(Object.prototype.__proto__ === null); // true

En JavaScript, cada objeto (¡la función también es un objeto!) Tiene una __proto__propiedad, la propiedad es referencia a su prototipo.

Cuando usamos el newoperador con un constructor para crear un nuevo objeto, la __proto__propiedad del nuevo objeto se establecerá con la prototypepropiedad del constructor , luego el constructor será llamado por el nuevo objeto, en ese proceso "esto" será una referencia al nuevo objeto en el ámbito del constructor, finalmente devuelve el nuevo objeto.

El prototipo del constructor es __proto__propiedad, la prototypepropiedad del constructor es trabajar con el newoperador.

El constructor debe ser una función, pero la función no siempre es un constructor, incluso si tiene una prototypepropiedad.

La cadena de prototipos en realidad es __proto__propiedad del objeto para hacer referencia a su prototipo, y la __proto__propiedad del prototipo para hacer referencia al prototipo del prototipo, y así sucesivamente, hasta hacer referencia a la __proto__propiedad del prototipo del Objeto que es referencia a nulo.

Por ejemplo:

console.log(a.constructor === A); // true
// "a" don't have constructor,
// so it reference to A.prototype by its ``__proto__`` property,
// and found constructor is reference to A

[[Prototype]]y la __proto__propiedad en realidad es lo mismo.

Podemos usar el método getPrototypeOf de Object para obtener el prototipo de algo.

console.log(Object.getPrototypeOf(a) === a.__proto__); // true

Cualquier función que escribimos puede usarse para crear un objeto con el newoperador, por lo que cualquiera de esas funciones puede ser un constructor.

林奕 忠
fuente
6

Otra buena forma de entenderlo:

var foo = {}

/* 
foo.constructor is Object, so foo.constructor.prototype is actually 
Object.prototype; Object.prototype in return is what foo.__proto__ links to. 
*/
console.log(foo.constructor.prototype === foo.__proto__);
// this proves what the above comment proclaims: Both statements evaluate to true.
console.log(foo.__proto__ === Object.prototype);
console.log(foo.constructor.prototype === Object.prototype);

Solo después de que IE11 __proto__sea ​​compatible. Antes de esa versión, como IE9, puede usar el constructorpara obtener el __proto__.

Yad Smood
fuente
Solo que lo escribiría al revés: foo .__ proto__ === foo.constructor.prototype
epeleg
6

prototipo

El prototipo es una propiedad de una función. Es el modelo para crear objetos usando esa función (constructor) con una nueva palabra clave.

__proto__se usa en la cadena de búsqueda para resolver métodos, propiedades. cuando se crea un objeto (usando la función de constructor con una nueva palabra clave), __proto__se establece en (Constructor) Function.prototype

function Robot(name) {
    this.name = name;
}
var robot = new Robot();

// the following are true   
robot.__proto__ == Robot.prototype
robot.__proto__.__proto__ == Object.prototype

Aquí está mi explicación (imaginaria) para aclarar la confusión:

Imagine que hay una clase imaginaria (blueprint / coockie cutter) asociada con la función. Esa clase imaginaria se usa para instanciar objetos. prototypees el mecanismo de extensión (método de extensión en C #, o Swift Extension) para agregar cosas a esa clase imaginaria.

function Robot(name) {
    this.name = name;
}

Lo anterior se puede imaginar como:

// imaginary class
class Robot extends Object{

    static prototype = Robot.class  
    // Robot.prototype is the way to add things to Robot class
    // since Robot extends Object, therefore Robot.prototype.__proto__ == Object.prototype

    var __proto__;

    var name = "";

    // constructor
    function Robot(name) {

        this.__proto__ = prototype;
        prototype = undefined;

        this.name = name;
    }

} 

Entonces,

var robot = new Robot();

robot.__proto__ == Robot.prototype
robot.prototype == undefined
robot.__proto__.__proto__ == Object.prototype

Ahora agregando método al prototyperobot:

Robot.prototype.move(x, y) = function(x, y){ Robot.position.x = x; Robot.position.y = y};
// Robot.prototype.move(x, y) ===(imagining)===> Robot.class.move(x, y)

Lo anterior se puede imaginar como una extensión de la clase Robot:

// Swift way of extention
extension Robot{
    function move(x, y){    
        Robot.position.x = x; Robot.position.y = y
    }
}

Que a su vez,

// imaginary class
class Robot{

    static prototype = Robot.class // Robot.prototype way to extend Robot class
    var __proto__;

    var name = "";

    // constructor
    function Robot(name) {

        this.__proto__ = prototype;
        prototype = undefined;

        this.name = name;
    }

    // added by prototype (as like C# extension method)
    function move(x, y){ 
        Robot.position.x = x; Robot.position.y = y
    };
}
Hassan Tareq
fuente
Todavía estoy pensando en nombres más coherentes para __proto__y prototipo. tal vez prototipo y herencia?
Dmitry
Yo diría, prototypey __proto__ambos deben ser evitados. Tenemos clase ahora y me gusta OOP.
Hassan Tareq
el problema es que la clase es relativamente nueva y no es compatible con motores realmente convenientes como microsoft JScript (es bueno tenerla cuando se trabaja en C y necesita un motor de script rápido y sucio que siempre esté ahí), y nashorn javascript (que viene con todos nuevas instalaciones de Java bajo jjs y es una buena manera de poner Java en un entorno dinámico puro donde no necesita recompilar cosas constantemente). La cuestión es que si la clase fuera azúcar, no sería un problema, pero no lo es, ofrece cosas que son imposibles sin ellas en versiones anteriores de js. Como extender "Función".
Dmitry
Eventualmente obtendremos apoyo. Soy desarrollador de back-end, así que no tengo problemas, codifico en js raramente.
Hassan Tareq
y heredar miembros estáticos de una manera que el niño notará la adición / eliminación de miembros estáticos de los padres (que no se me ocurre una forma de hacerlo en JScript, que no ofrece Object.assign / __ proto __ / getPrototypeOf, por lo que tiene que jugar con el objeto raíz.prototipo para simularlo)
Dmitry
4

Para hacerlo mas simple:

> var a = 1
undefined
> a.__proto__
[Number: 0]
> Number.prototype
[Number: 0]
> Number.prototype === a.__proto__
true

Esto le permite adjuntar propiedades a X.prototype DESPUÉS de que se hayan instanciado objetos de tipo X, y aún así tendrán acceso a esas nuevas propiedades a través de la referencia __proto__ que el motor Javascript usa para subir por la cadena de prototipos.

Andreas Bergström
fuente
4

Prototype u Object.prototype es una propiedad de un objeto literal. Representa el objeto prototipo del Objeto que puede anular para agregar más propiedades o métodos a lo largo de la cadena del prototipo.

__proto__ es una propiedad de acceso (función get y set) que expone el prototipo interno de un objeto a través del cual se accede.

Referencias

  1. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/prototype
  2. http://www.w3schools.com/js/js_object_prototypes.asp

  3. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/proto

akodevs
fuente
Object.prototypeno es una propiedad de un objeto literal, intentar imprimir {}.prototyperetornos indefinidos; sin embargo, se puede acceder a través de {}.__proto__, que regresa Object.prototype.
doubleOrt
3

Lo sé, llego tarde pero déjame intentar simplificarlo.

Digamos que hay una función

    function Foo(message){

         this.message = message ; 
     };

     console.log(Foo.prototype);

La función Foo tendrá un objeto prototipo vinculado. Entonces, cada vez que creamos una función en JavaScript, siempre tiene un objeto prototipo vinculado.

Ahora sigamos adelante y creemos dos objetos usando la función Foo.

    var a = new Foo("a");
    var b = new Foo("b");
    console.log(a.message);
    console.log(b.message);
  1. Ahora tenemos dos objetos, el objeto a y el objeto b. Ambos se crean utilizando el constructor Foo. Tenga en cuenta que constructor es solo una palabra aquí.
  2. Los objetos ayb tienen una copia de la propiedad del mensaje.
  3. Estos dos objetos ayb están vinculados al objeto prototipo del constructor Foo.
  4. En los objetos ayb, podemos acceder al prototipo de Foo usando la propiedad proto en todos los navegadores y en IE podemos usar Object.getPrototypeOf (a) u Object.getPrototypeOf (b)

Ahora, Foo.prototype, a. proto , y b. proto all denota el mismo objeto.

    b.__proto__ === Object.getPrototypeOf(a);
    a.__proto__ ===  Foo.prototype;
    a.constructor.prototype  === a.__proto__;

todo lo anterior volvería verdadero.

Como sabemos, en JavaScript las propiedades se pueden agregar dinámicamente. Podemos agregar propiedad al objeto

    Foo.prototype.Greet = function(){

         console.log(this.message);
    }
    a.Greet();//a
    b.Greet();//b
    a.constructor.prototype.Greet();//undefined 

Como puede ver, agregamos el método Greet () en Foo.prototype pero es accesible en ayb o en cualquier otro objeto que se construya usando Foo.

Al ejecutar a.Greet (), JavaScript primero buscará Greet en el objeto a en la lista de propiedades. Al no encontrarlo, subirá en la cadena de proto de a. Desde un. proto y Foo.prototype es el mismo objeto, JavaScript encontrará el método Greet () y lo ejecutará.

Espero, ahora prototipo y proto se simplifica un poco.

modo de depuración
fuente
3

Ejemplo explicativo:

function Dog(){}
Dog.prototype.bark = "woof"

let myPuppie = new Dog()

ahora, myPupppie tiene una __proto__propiedad que apunta a Dog.prototype.

> myPuppie.__proto__
>> {bark: "woof", constructor: ƒ}

pero myPuppie NO tiene una propiedad prototipo.

> myPuppie.prototype
>> undefined

Entonces, __proto__de mypuppie es la referencia a la propiedad .prototype de la función constructora que se usó para instanciar este objeto (y el objeto myPuppie actual tiene una relación de "delegados a" con este __proto__objeto), mientras que la propiedad .prototype de myPuppie simplemente está ausente (ya que no lo configuramos).

Buena explicación por MPJ aquí: proto vs prototipo - Creación de objetos en JavaScript

Nitin Jadhav
fuente
3

Me hice un pequeño dibujo que representa el siguiente fragmento de código:

var Cat = function() {}
var tom = new Cat()

Comprender el __proto__ y el prototipo

Tengo un fondo clásico de OO, por lo que fue útil representar la jerarquía de esta manera. Para ayudarlo a leer este diagrama, trate los rectángulos de la imagen como objetos JavaScript. Y sí, las funciones también son objetos. ;)

Los objetos en JavaScript tienen propiedades y __proto__es solo uno de ellos.

La idea detrás de esta propiedad es apuntar al objeto ancestro en la jerarquía (herencia).

El objeto raíz en JavaScript es Object.prototypey todos los demás objetos son descendientes de este. La __proto__propiedad del objeto raíz es null, que representa el final de la cadena de herencia.

Notarás que prototypees una propiedad de las funciones. Cates una función, pero también Functiony Objectson funciones (nativas). tomno es una función, por lo tanto no tiene esta propiedad.

La idea detrás de esta propiedad es apuntar a un objeto que se utilizará en la construcción, es decir, cuando llame al newoperador en esa función.

Tenga en cuenta que los objetos prototipo (rectángulos amarillos) tienen otra propiedad llamada constructorque apunta de nuevo al objeto de función respectivo. Por razones de brevedad esto no fue representado.

De hecho, cuando creamos el tomobjeto con new Cat(), el objeto creado tendrá la __proto__propiedad establecida en el prototypeobjeto de la función constructora.

Al final, juguemos un poco con este diagrama. Las siguientes afirmaciones son verdaderas:

  • tom.__proto__la propiedad apunta al mismo objeto que Cat.prototype.

  • Cat.__proto__señala al Function.prototypeobjeto, al igual que Function.__proto__y Object.__proto__hacer.

  • Cat.prototype.__proto__y tom.__proto__.__proto__apuntan al mismo objeto y eso es Object.prototype.

¡Salud!

theshinylight
fuente
Muy bien explicado!
StackOverflow UI
@theshinylight, tom.__proto__y Cat.prototypeson estrictamente iguales, entonces,tom.__proto__ === Cat.prototype y Cat.prototype === tom.__proto__son ciertas. Entonces, ¿qué quisiste decir con la flecha en la imagen?
aXuser264
La flecha negra (si se refiere a ella) no tiene un significado particular, aparte de la propiedad del objeto. Entonces, prototypees propiedad del Catobjeto (de su pregunta).
theshinylight
2

Definiciones

(el número dentro del paréntesis () es un 'enlace' al código que se escribe a continuación)

prototype- un objeto que consiste en:
=> funciones (3) de este particular ConstructorFunction.prototype(5) que son accesibles por cada objeto (4) creado o por crear mediante esta función constructora (1)
=> la función constructora misma (1) )
=> __proto__de este objeto en particular (objeto prototipo)

__proto__(¿proto de proveedor?): un enlace ENTRE cualquier objeto (2) creado a través de una función de constructor particular (1), Y las propiedades del objeto prototipo (5) de ese constructor QUE permite que cada objeto creado (2) tenga acceso a las funciones del prototipo y métodos (4) ( __proto__se incluye por defecto en cada objeto en JS)

CLARIFICACIÓN DEL CÓDIGO

1)

    function Person (name, age) {
        this.name = name;
        this.age = age;} 

2)

    var John = new Person(‘John’, 37);
    // John is an object

3)

    Person.prototype.getOlder = function() {
        this.age++;
    }
    // getOlder is a key that has a value of the function

4)

    John.getOlder();

5)

    Person.prototype;
Eduard
fuente
1

Probaré una explicación de cuarto grado:

Las cosas son muy simples. A prototypees un ejemplo de cómo se debe construir algo. Entonces:

  • Soy functionay construyo nuevos objetos similares a miprototype

  • Soy un objecty fui construido usando mi __proto__como ejemplo

prueba :

function Foo() { }

var bar = new Foo()

// `bar` is constructed from how Foo knows to construct objects
bar.__proto__ === Foo.prototype // => true

// bar is an instance - it does not know how to create objects
bar.prototype // => undefined
vladCovaliov
fuente
1
No, ni a prototypeni __proto__se utilizan en ningún momento como un plano o algo así para crear cualquier objeto. Este es un mito introducido por la classsintaxis borrosa y sus predecesores. Como dice el post de respuesta, solo se usa para la cadena de búsqueda y en caso de prototypeidentificarse constructorcon new(que es parte de ese mecanismo de simulación de clase que está confundiendo a muchos usuarios, incluido yo).
Christof Kälin
El primer punto debería ser "Soy una función y construyo nuevos objetos que delegarán en mi prototipo"
Nitin Jadhav
1

Cada función que crea tiene una propiedad llamada prototype, y comienza su vida como un objeto vacío. Esta propiedad no sirve de nada hasta que utilice esta función como función constructora, es decir, con la palabra clave 'new'.

Esto a menudo se confunde con la __proto__propiedad de un objeto. Algunos pueden confundirse y, salvo que la prototypepropiedad de un objeto puede obtener el protocolo de un objeto. Pero este no es el caso. prototypese usa para obtener __proto__un objeto creado a partir de un constructor de funciones.

En el ejemplo anterior:

function Person(name){
    this.name = name
}; 

var eve = new Person("Eve");

console.log(eve.__proto__ == Person.prototype) // true
// this is exactly what prototype does, made Person.prototype equal to eve.__proto__

Espero que tenga sentido.

Malkeet Singh
fuente
1
prototypeno se usa para crear el __proto__de un objeto. __proto__, cuando se accede, simplemente proporciona una referencia al prototypeobjeto.
doubleOrt
1

¿Qué pasa con el uso __proto__de métodos estáticos?

function Foo(name){
  this.name = name
  Foo.__proto__.collection.push(this)
  Foo.__proto__.count++

}

Foo.__proto__.count=0
Foo.__proto__.collection=[]

var bar = new Foo('bar')
var baz = new Foo('baz')

Foo.count;//2
Foo.collection // [{...}, {...}]
bar.count // undefined
Barrard
fuente
Eso es exactamente por qué una respuesta a " __proto__VS. prototypeen JavaScript" ?
Andreas
¿es bueno o qué pasa con Foo.collection.push (esto) Foo.count ++
Selva Ganapathi
1

(function(){ 
      let a = function(){console.log(this.b)};
      a.prototype.b = 1;
      a.__proto__.b = 2;
      let q = new a();
      console.log(a.b);
      console.log(q.b) 
    })()

Prueba este código para entender

Timur
fuente
1

Solo hay un objeto que se usa para el encadenamiento protípico. Este objeto obviamente tiene un nombre y un valor: __proto__es su nombre y prototypees su valor. Eso es todo.

para que sea aún más fácil de entender, mire el diagrama en la parte superior de esta publicación (Diagrama de dmitry soshnikov), nunca encontrará __proto__puntos para otra cosa que no sea prototypesu valor.

La esencia es esta: __proto__es el nombre que hace referencia al objeto prototípico, yprototype es el objeto prototípico real.

Es como decir:

let x = {name: 'john'};

xes el nombre del objeto (puntero) y {name: 'john'}es el objeto real (valor de datos).

NOTA: esto es solo una pista enormemente simplificada sobre cómo se relacionan en un nivel alto.

Actualización: Aquí hay un ejemplo simple de JavaScript concreto para una mejor ilustración:

let x = new String("testing") // Or any other javascript object you want to create

Object.getPrototypeOf(x) === x.__proto__; // true

Esto significa que cuando Object.getPrototypeOf(x)nos obtiene el valor real de x(que es su prototipo), es exactamente lo que el __proto__de xestá apuntando. Por __proto__lo tanto, de hecho está apuntando al prototipo de x. Por lo tanto, hace __proto__referencia x(puntero de x) y prototypees el valor de x(su prototipo).

Espero que esté un poco claro ahora.

Fouad Boukredine
fuente
1

Esta es una pregunta muy importante relevante para cualquiera que quiera entender la herencia prototípica. Por lo que entiendo, el prototipo se asigna de manera predeterminada cuando se crea un objeto con nuevo de una función porque la función tiene un objeto prototipo por definición:

function protofoo(){
}
var protofoo1 = new protofoo();
console.log(protofoo.prototype.toString()); //[object Object]

Cuando creamos un objeto ordinario sin recursos nuevos, es decir explícitamente de una función, que no tiene un prototipo pero tiene un vacío proto que se puede asignar un prototipo.

var foo={
  check: 10
};
console.log(foo.__proto__); // empty
console.log(bar.prototype); //  TypeError
foo.__proto__ = protofoo1; // assigned
console.log(foo.__proto__); //protofoo

Podemos usar Object.create para vincular un objeto explícitamente.

// we can create `bar` and link it to `foo`
var bar = Object.create( foo );
bar.fooprops= "We checking prototypes";
console.log(bar.__proto__); // "foo"
console.log(bar.fooprops); // "We checking prototypes"
console.log(bar.check); // 10 is delegated to `foo`
tksilicon
fuente
0

__proto__es la base para construir prototypey una función constructora, por ejemplo: function human(){}has prototypeque se comparte a través __proto__de la nueva instancia de la función constructora. Una lectura más detallada aquí

Jyoti Duhan
fuente
@Derick Daniel: no estoy seguro de por qué rechazaste esto, pero la edición que hiciste no fue lo que estaba tratando de transmitir. Lo edité más para obtener más espacio :).
Jyoti Duhan
Jyoti, no rechacé tu respuesta, alguien más lo hizo, solo la edité :)
Freelancer
0

A medida que este declaró acertadamente

__proto__es el objeto real que se usa en la cadena de búsqueda para resolver métodos, etc. prototype es el objeto que se usa para construir __proto__cuando se crea un objeto con nuevo:

( new Foo ).__proto__ === Foo.prototype;
( new Foo ).prototype === undefined;

Además, podemos observar que la __proto__propiedad de un objeto creado utilizando el constructor de funciones apunta hacia la ubicación de la memoria apuntada por la propiedad prototipo de ese constructor respectivo.

Si cambiamos la ubicación de la memoria del prototipo de la función del constructor, el __proto__objeto derivado seguirá apuntando hacia el espacio de direcciones original. Por lo tanto, para hacer que la propiedad común esté disponible en la cadena de herencia, siempre agregue la propiedad al prototipo de la función del constructor , en lugar de reinicializarla (lo que cambiaría su dirección de memoria).

Considere el siguiente ejemplo:

function Human(){
    this.speed = 25;
}

var himansh = new Human();

Human.prototype.showSpeed = function(){
    return this.speed;
}

himansh.__proto__ === Human.prototype;  //true
himansh.showSpeed();    //25

//now re-initialzing the Human.prototype aka changing its memory location
Human.prototype = {lhs: 2, rhs:3}

//himansh.__proto__ will still continue to point towards the same original memory location. 

himansh.__proto__ === Human.prototype;  //false
himansh.showSpeed();    //25
Himansh
fuente
-1

mi entendimiento es: __proto__ y prototipo se sirven para la técnica de la cadena de prototipos. la diferencia es que las funciones nombradas con guión bajo (como __proto__) no están destinadas a los desarrolladores invocados explícitamente. en otras palabras, son solo para algunos mecanismos como heredar, etc. son 'back-end'. pero las funciones nombradas sin guión bajo están diseñadas para invocarse explícitamente, son 'front-end'.

Beicai
fuente
3
Hay más para __proto__y prototype, que solo la convención de nomenclatura. Pueden o no apuntar al mismo objeto. Ver @zyklus respuesta.
retiro el
1
@demisx, por supuesto, dijiste que es correcto, pero mi opinión es que la diferencia de nombre expone el contraste de la funcionalidad.
Beicai
No es suficiente decir "según su comprensión", especialmente cuando se han proporcionado otras buenas respuestas antes ...
ProfNandaa
-3

¡¡¡ESTA ES LA MEJOR EXPLICACIÓN DEL MUNDO !!!!!

var q = {}
var prototype = {prop: 11}

q.prop // undefined
q.__proto__ = prototype
q.prop // 11

en los constructores de funciones, el motor de JavaScript lo llama q.__proto__ = prototypeautomáticamente cuando escribimos new Class, y en el __proto__conjunto de accesoriosClass.prototype

function Class(){}
Class.prototype = {prop: 999} // set prototype as we need, before call new

var q = new Class() // q.__proto__ = Class.prototype
q.prop // 999

Disfruta%)

Maxmaxmaximus
fuente