javascript prototype vs __proto__

Siempre me surge la misma duda, la miro, me entero, y me vuelvo a olvidar.

¿Cuál es la diferencia entre prototype y __proto__?

Tras leer el artículo JavaScript. The Core por Dmitry Soshnikov para conocer la diferencia (como hice yo), este diagrama de dicho artículo  lo resume bien:

http://dmitrysoshnikov.com/ecmascript/javascript-the-core/

http://dmitrysoshnikov.com/ecmascript/javascript-the-core/

Mi explicación simplicada:

  • __proto__ es el atributo que se consulta en tiempo de ejecución para ver a qué se accede si la instancia no posee dicho atributo. Por así decirlo, es la cadena de mando en la ejecución de métodos (y acceder a atributos) de instancias.
    En el diagrama, la instancia “b” hereda de “Foo” (__proto__ -> Foo.prototype) que a su vez hereda de “Object” (__proto__ -> Object.prototype).
  • prototype es un atributo que poseen las funciones que van a servir como constructor de objetos, y dicho atributo es el que se establecerá a __proto__ a las instancias. Por así decirlo, prototype es la definición de la clase.
  • new lo que hace es: crea la variable (por ejemplo “b”), y asigna “__proto__ = Clase.prototype” (pongo clase en cursiva porque en javascript no son clases)

De este modo vemos en el diagrama que Foo tiene prototype y __proto__:

  • Como Foo es una función, su __proto__ hace referencia a Function.
  • pero como Foo se va a utilizar como si fuera una clase, para instanciar objetos, tiene un prototype que va a ser la definición de la “clase“, a la que hacen referencia __proto__ de las instancias.

Detalles a mayores:

  • Los atributos/métodos en prototype son compartidos en modo lectura por todas las instancias. El motor de javascript se encarga de “convertir” b.x en b.__proto__.x cuando b no posee él mismo el atributo x.
  • Cuando modificas b.x del diagrama, el motor de javascript hace una copia (copy-on-write), de manera que b pasa a tener él mismo un atributo “x” diferente a __proto__.x. Las siguientes veces que accedas a b.x, el motor no lo transformará en b.__proto__.x, sino que tomara el valor del propio atributo de b.
    constructor-proto-chain-copy-on-write
  • Si se quiere tratar un atributo de clase (atributos estáticos, vamos) como tal, hay que hacer referencia siempre a b.__proto__.x, y al modificar esta variable de esta manera sí que se modifica para todas las instancias (que también han de acceder al valor mediante b.__proto__.x).

Más información en StackOverflow.

Leave a Reply

Your email address will not be published.