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.

Javascript y las funciones recursivas

Estaba programando en el trabajo, y resulta que mi función recursiva no funcionaba bien… ¿y qué era? Pues que en las funciones recursivas se han de declarar las variables locales con “var nombrevariable…” puesto que si no, curiosamente, las variables se comportan como compartidas en todas las llamadas a la función y termina machacada y machacada.

Yo no lo sabía :S (es lo que tiene tener que hacer las cosas sin tiempo a leerse manuales).

ACTUALIZACIÓN:

Leyendo Javascript: The Definitive Guide (espero compármelo algún día, y en formato ePub!), he encontrado la explicación a la cuestión. Concretamente las secciones 2 y 3 del capítulo 4.

Si defines una variable sin la palabra reservada var, Javascript automáticamente la declara por tí como variable global.

Vaya cosas. Lo que hace no tener tiempo para leer buenos manuales… :\

[EOF]