En javascript, cada objeto tiene una propiedad constructor que se refiere a la función constructor que inicializa el objeto.Suena bien: hace que los constructores parezcan estáticos como las clases en Java. Incluso la sintaxis
new Constructor()
parece igual:
function MyConstructor() {}
var myobject = new MyConstructor();
myobject.constructor == MyConstructor; // true
Pero la vida no es tan simple:
function MyConstructor() {}
MyConstructor.prototype = {};
var myobject = new MyConstructor();
myobject.constructor == MyConstructor; // false
¿Qué pasa? Algunas definiciones
Objetos y métodos
Los objetos en Javascript son simples bolsas de propiedades con nombre que pueden ser leidas y escritas. Para la mayoría de propósitos, javascript no tiene clases. [1]Las funciones en javascript son objetos de primera clase. Los métodos en javascript son sólo propiedades que son funciones.
Prototipos
El prototipo (prototype) de un objeto es una propiedad interna a la que me referire como "[[Prototype]]" (como en Ecma-262). En otras palabras,obj.prototype
en general no es el [[Prototype]] de obj
. El estándar no provee una forma de recuperar la propiedad [[Prototype]] de un objeto.Los objetos javascript pueden delegar propiedades a su [[Prototype]] (y su [[Prototype]] puede hacer lo mismo; y así hasta Object Prototype).
Búsqueda de propiedades
Cuando una propiedad "propname" de un objeto es leida, el sistema comprueba si ese objeto tiene una propiedad llamada "propname". Si esa propiedad no existe, el sistema comprueba el [[Prototype]] del objeto para encontrar la propiedad, y así recursivamente.Esto significa que los objetos que comparten un mismo [[Prototype]] tambien comparten las propiedades definidas en ese [[Prototype]].
Cuando una propiedad "propname" de un objeto se establece, la propiedad se inserta en ese objeto, ignorando la cadena [[Prototype]] de ese objeto (y ocultando cualquier propiedad del mismo nombre en la cadena de prototipos).
La propiedad [[Prototype]] se inicializa desde la propiedad (pública) "prototype" de la función constructor, cuando ésta es llamada.
¿Qué está pasando? Línea por línea.
Esto es lo que las propiedades prototype y [[Prototype]] parecen. Las elipses son objetos, las flechas son propiedades que referencia a otros objetos. La/s cadena/s [[Prototype]] están en verde.#1: function MyConstructor() {}
Bastante simple.
MyConstructor.prototype
es una propiedad que es automáticamente creada, la cual en cambio tiene una propiedad constructor
que apunta a MyConstructor
. Recuerda eso: los únicos objetos que de hecho tienen una propiedad constructor
por defecto son las propiedades de funciones prototype
que se crean automáticamente.El resto no es realmente relevante pero podría confundir e iluminar (con suerte en ese orden):
El [[Prototype]] de
MyConstructor
es Function.prototype, no MyConstructor.prototype
. Nótese también que la cadena [[Prototype]] de cada objeto termina en el Object.prototype
.El [[Prototype]] de
Object.prototype
es realmente null
indicando que es el final de la cadena.
Para los siguientes pasos, estoy dejando la cadena [[Prototype]] de MyConstructor
por claridad, ya que no cambia y no es relevante.
#2: MyConstructor.prototype = {}
Ahora hemos terminado con el objeto
MyConstructor.prototype
predefinido y lo hemos sustituido con un objeto anónimo, mostrado aquí como "{}". Este objeto no tiene propiedad constructor,
#3: var myobject = new MyConstructor()
De este grafo, siguiendo las reglas de búsqueda de propiedades, podemos ahora ver que myobject.constructor es delegado a Object.prototype.constructor, el cual apunta a Object. En otras palabras:
function MyConstructor() {}
MyConstructor.prototype = {};
var myobject = new MyConstructor();
myobject.constructor == Object
¿Y qué pasa con instanceof
?
Javascript facilita el operador instanceof que pretende comprobar la cadena de prototipos del objeto con el que estás tratando. A partir de lo de antes, podrías pensar que lo siguiente devolvería false
:
function MyConstructor() {}
MyConstructor.prototype = {};
var myobject = new MyConstructor();
myobject instanceof MyConstructor // true
Pero el hecho es que funciona (pulsa el botón). También nota que myobject delega en Object.prototype:
function MyConstructor() {}
MyConstructor.prototype = {};
var myobject = new MyConstructor();
myobject instanceof Object
Cuando se llama a
instanceof
, comprueba la propiedad prototype
del constructor dado y comprueba la cadena [[Prototype]] del objeto dado. En otras palabras, no depende de la propiedad constructor
.Todo muy bonito, pero tu puedes aún romperlo si lo intentas con ganas:
function MyConstructor() {}
var myobject = new MyConstructor();
MyConstructor.prototype = {};
[ myobject instanceof MyConstructor, // false !
myobject.constructor == MyConstructor, // true !
myobject instanceof Object ] // true
Así quedan las cadenas de prototipos tras ejecutar eso:
Los constructores no son clases
En un sistema de objetos basado en clases, las clases típicamente heredan de otras, y los objetos son instancias de esas clases. Los métodos y propiedades que son compartidos entre instancias son (al menos conceptualmente) propiedades de clases. Las propiedades (y para algunos lenguajes, métodos) que no deben ser compartidos son propiedades de los mismos objetos.Los constructores de javascript no hacen nada parecido: de hecho los constructores tienen su propia cadena [[Prototype]] completamente separada de la cadena [[Prototype]] de objetos que ellos inicializan.
Los constructores no funcionan como inicializadores basados en clases
Una llamada a constructor asocia un nuevo objeto con un [[Prototype]]. La función constructor podría establecer propiedades adicionales sobre el objeto. Las llamadas a constructor no llaman constructores "heredados", y no deberían porque el [[Prototype]] del objeto (elprototype
del constructor) se supone que está compartido y (probablemente) ya inicializado.
Los constructores sólo son funciones
Cualquier función definida por el usuario en javascript automáticamente obtiene una propiedadprototype
que, en cambio, tiene una propiedad constructor
que se refiere (de vuelta) a la función.Cualquier función definida por el usuario puede ser llamada como constructor anteponiéndole
new
a la llamada. Esto pasará un nuevo objeto this
a la funcion, y su propiedad [[Prototype]] se inicializará a la propiedad prototype
de la función.
Notas al pie
[1] Hay clases definidas por el sistema: Function, Object, Array, Class, RegExp, Boolean, Number, Math, Date, Error y String. Un usuario no puede añadir una nueva clase, aunque el sistema podría definir más. Nótese que estas clases no son las misma que los objetos predefinidos (constructores) con el mismo nombre, y no pueden ser directamente accedidas de ninguna forma.Un constructor definido por el usuario que no devuelve explícitamente algo más siempre devuelve un objeto de la clase Object.
Referencias
A comp.lang.javascript question
Subject: "x.constructor == Foo" vs "x instanceof Foo".
Message-ID: <fniu6a$2cn$1@reader2.panix.com
>
http://groups.google.com/group/comp.lang.javascript/msg/102ab20c68aa738f
Ecma-262
Standard ECMA-262. ECMAScript Language Specification 3rd edition (December 1999) http://www.ecma-international.org/publications/standards/Ecma-262.htm
Flanagan 2006
JavaScript: The Definitive Guide, Fifth Edition. ISBN 10: 0-596-10199-6 | ISBN 13:9780596101992
Author & copyright
(c)2008 Joost Diepenmaat, Zeekat Softwareontwikkeling.
Quiero iniciarme a fondo en javascript, pero al tratar de programar con objetos, no puedo comprender cual es la importacion de la palabra prototype...
ResponderEliminarHe buscado por la red y solo encuentro la libreria Prototype, pero nada qeu me saque de mis dudas....
Si tiene algun documento donde se explica con mas detalle el uso de la palabra prototype, estaria agradecido me lo hciera llegar...
Mi correo es r_quinteroa@hotmail.com..
Saludos..
gustirijillo ^^
ResponderEliminar