En los objetos literales no se diferencian realmente propiedades y métodos, básicamente las propiedades que contienen una función se las llama métodos, pero no se distinguen en nada más. En las clases la cosa cambia un poco, las propiedades que contienen cualquier dato que no sea una función se suelen definir en el propio objeto y las propiedades que contienen una función, es decir, los métodos, son definidos como miembros del prototipo. Vamos a ver con más detalle.
definición en el constructor
class | function |
class C { constructor ( x ) { this.x = x; } } const c = new C( 1 ); console.assert( c.x === 1 ); | function C ( x ) { this.x = x; } const c = new C( 1 ); console.assert( c.x === 1 ); |
La forma más habitual de crear propiedades es añadiéndolas al objeto this
en el constructor. De esta manera podemos crear cualquier tipo de propiedades en el objeto, simplemente hay que asignarles un valor. De esta forma cada objeto tiene sus propias propiedades que pueden contener valores únicos por instancia.
Aunque en una próxima especificación se permitirá incluir directamente campos en las clases, de momento no existe forma de especificar propiedades en el cuerpo de una instrucción class
y debemos asignarlas en el constructor.
propiedades enumerables y no enumerables
Por defecto, las propiedades creadas en el constructor asignándolas al this
son enumerables, es decir, son consideradas cuando se recorren las propiedades con instrucciones como for...in
. No obstante, podemos modificar las características de las propiedades de forma específica:
class | function |
class C { constructor ( x, y ) { this.x = x; Object.defineProperty( this, 'y', { value : y, enumerable : false } ); } } const c = new C( 1, 2 ); console.assert( c.propertyIsEnumerable( 'x' ) ); console.assert( ! c.propertyIsEnumerable( 'y' ) ); | function C ( x, y ) { this.x = x; Object.defineProperty( this, 'y', { value : y, enumerable : false } ); } const c = new C( 1, 2 ); console.assert( c.propertyIsEnumerable( 'x' ) ); console.assert( ! c.propertyIsEnumerable( 'y' ) ); |
En todos los casos podemos utilizar los métodos Object.defineProperty()
y Object.defineProperties()
para configurar las características que queremos que tengan las propiedades.
modificar propiedades en el objeto
class | function |
class C { constructor () { this.x = 1; } } const c = new C(); c.x = 2; c.a = 10; console.assert( c.x === 2 ); console.assert( c.a === 10 ); | function C () { this.x = 1; } const c = new C(); c.x = 2; c.a = 10; console.assert( c.x === 2 ); console.assert( c.a === 10 ); |
Por defecto, los miembros de los objetos construidos a partir de una clase pueden modificarse sin limitación alguna. Podemos borrar propiedades, añadir nuevos miembros o modificar el valor de los ya existentes. Las propiedades creadas en el constructor y las creadas posteriormente no se diferencian, siendo ambas miembros del objeto de iguales características:
Si queremos limitar la posibilidad de modificar o añadir propiedades podemos hacer uso en el constructor de Object.seal()
, Object.freezen()
o Object.preventExtensions()
.
class | function |
class C { constructor () { this.x = 1; return Object.seal( this ); } } const c = new C(); c.x = 2; c.a = 10; console.assert( c.x === 2 ); console.assert( typeof c.a === 'undefined' ); console.assert( Object.isSealed( c ) ); | function C () { this.x = 1; return Object.seal( this ); } const c = new C(); c.x = 2; c.a = 10; console.assert( c.x === 2 ); console.assert( typeof c.a === 'undefined' ); console.assert( Object.isSealed( c ) ); |
En este ejemplo hemos bloqueado la posibilidad de añadir nuevas propiedades al objeto por medio de una llamada a Object.seal()
, pero seguimos pudiendo modificar el valor de las propiedades ya existentes.
propiedades en el prototipo
Aunque habitualmente las propiedades se crean directamente sobre el objeto, nada nos impide crearlas de forma explícita en el prototipo y compartirlo entre todas las instancias de la clase.
class | function |
class C { } C.prototype.x = 1; C.prototype.y = 2; const c = new C(); console.assert( c.x === 1 ); console.assert( c.y === 2 ); console.assert( c.y === C.prototype.y ); c.y = 3; console.assert( c.y === 3 ); console.assert( c.y !== C.prototype.y ); | function C () { } C.prototype.x = 1; C.prototype.y = 2; const c = new C(); console.assert( c.x === 1 ); console.assert( c.y === 2 ); console.assert( c.y === C.prototype.y ); c.y = 3; console.assert( c.y === 3 ); console.assert( c.y !== C.prototype.y ); |
Si en un objeto modificamos las propiedades definidas en su prototipo, entonces se crea una propiedad en el propio objeto, quedando oculta la propiedad del prototipo, que se comparte entre todos los objetos de la misma clase y no es posible modificarla desde el objeto.
Como se puede comprobar en el ejemplo, el objeto tiene ahora una propiedad y
con valor 3
y el prototipo también tiene una propiedad y
, pero esta mantiene el valor inicial de 2
.
Por último, hay que saber que las propiedades definidas en el prototipo son siempre no enumerables para el objeto, por que no aparecerán, por ejemplo, al invocar a JSON.stringify()
. Es algo que tenemos que tener en cuenta para evitar confusiones.
constructor | Índice | métodos |