Diferencia entre revisiones de «Configurar propiedades de clases en javascript»

De ChuWiki
Saltar a: navegación, buscar
m (Página creada con '__TOC__ En javascript podemos definir una clase con propiedades o atributos de esta forma var a = {x:11, y:22} Estas propiedades son por defecto visibles y modificables, per…')
 
m
 
(No se muestran 4 ediciones intermedias de 2 usuarios)
Línea 26: Línea 26:
 
  Object.defineProperty(a, "x", { value:11, writable:true, enumerable:true, configurable:true});
 
  Object.defineProperty(a, "x", { value:11, writable:true, enumerable:true, configurable:true});
  
 +
Un detalle a tener en cuenta. Si la propiedad es nueva, los valores por defecto para cada opción son false, por lo que si no rellenamos alguna, será false. En el siguiente caso por ejemplo
  
 +
var a = Object.defineProperty({}, "x", {value:11});
 +
 +
la propiedad x no será writable, no será enumerable y no será configurable. Si la propiedad ya existe, entonces las opcoines que no pongamos no se modificarán y permanecerán como ya las tuviera la propiedad. Por ejemplo, si hacemos
 +
 +
var a = {x:11};  // es writable, enumerable y configurable por defecto al definirla asi
 +
Object.setProperty(a, "x", {writable:false});  // Ahora es no writable, pero sigue siendo enumerable y configurable.
  
 
== value ==
 
== value ==
Línea 36: Línea 43:
 
  // ahora a.x vale 11
 
  // ahora a.x vale 11
  
 +
Como comentábamos antes, al no poner el resto de opciones, esta a.x es no writable, no enumerable y no configurable.
 +
 +
 +
== writable ==
 +
 +
Si definimos así la propiedad
 +
 +
var a = Object.defineProperty({}, "x", {value:11, writable:false});
 +
 +
La propiedad vale 11 y no se puede modificar. Si hacemos
 +
 +
a.x=22;
 +
 +
no dará error, pero a.x seguirá valiendo 11. Un detalle a tener en cuenta es que si la propiedad no es writable, pero sí es configurable, podemos cambiar su valor a través de defineProperty. Por ejemplo
 +
 +
var a = Object.defineProperty({}, "x", {value:11, writable:false, configurable:true});
 +
Object.defineProperty(a, "x", {value:22});  // Esto cambia el valor aunque sea no writable. Ahora x.a vale 22
 +
 +
 +
== enumerable ==
 +
 +
Si definimos un objeto así
 +
 +
var a = {x:11, y:22};
 +
 +
podemos hacer un bucle para recorrer cada una de sus propiedades de esta forma
 +
 +
for ( propiedad in a ) {
 +
    console.log (propiedad);  // Va escribiendo cada propiedad
 +
}
 +
// Esto saca en pantalla
 +
// x
 +
// y
 +
 +
Pues bien, si hacemos que una propiedad sea no enumerable, no aparecera al recorrerla con este tipo de bucle
 +
 +
Object.defineProperty (a, "x", {enumerable:false});
 +
for ( propiedad in a ) {
 +
    console.log (propiedad);  // Va escribiendo cada propiedad
 +
}
 +
// Esto saca en pantalla solo la y
 +
// y
 +
 +
 +
== configurable ==
 +
 +
Esta es la opción que nos indica si vamos a poder usar el defineProperty() más adelante otra vez para cambiar algo o no. Si no es configurable, no podemos volver a cambiar nada, excepto hacer cambiar writable true por false. Por ejemplo, si hacemos
 +
 +
var a = {x:1};
 +
Object.defineProperty(a, "x", {configurable:false});
 +
 +
a partir de aquí obtenemos error con cualquiera de las siguientes
 +
 +
Object.defineProperty(a, "x", {configurable:true});
 +
Object.defineProperty(a, "x", {writable:true});
 +
Object.defineProperty(a, "x", {value:2});
 +
// Dan error "TypeError: Cannot redefine property: x"
 +
 +
== setters y getters ==
 +
 +
A la hora de definir una propiedad con defineProperty(), en vez de indicar las opciones value y writable, podemos indicar las opciones get y set, pasando una función a esas opciones. Cuando intentemos acceder para leer la propiedad, se ejecutará la función get, cuando lo intentemos en modo escritura, se ejecutará la opción set. En el siguiente ejemplo
 +
 +
<pre>
 +
var a = Object.defineProperty ({}, "x", {
 +
  get : function() {return Math.random();},
 +
  set : function(valor) {console.log('me pasan '+valor)},
 +
  enumerable:true,
 +
  configurable:true})
 +
</pre>
 +
 +
Si intentamos acceder a a.x para leer, obtendremos cada vez un número aleatorio
 +
 +
<pre>
 +
> a.x
 +
0.28053418290801346
 +
</pre>
 +
 +
Si estamos con [[Depurar javascript con Chrome|algún debugger de javascript con console]] como el de google chrome, cada vez que intenemos fijar un valor a a.x se sacará por pantalla un texto indicándolo, pero no se guardará nada.
 +
 +
<pre>
 +
> a.x=33
 +
me pasan 33
 +
</pre>
 +
 +
Esto puede tener en algún momento dado alguna utilidad, pero su verdadera utilida es cuando a través de estos métodos set y get accedermos y modificamos otros atributos de la clase. Por ejemplo, podemos tener un atributo x y un método getter/setter doble, de forma que nos devuelva el doble de x o haga que x sea la mitad
 +
 +
<pre>
 +
var a = Object.defineProperty ({x:11}, "doble", {
 +
  get : function() {return this.x*2;},
 +
  set : function(valor) {this.x=valor/2},
 +
  enumerable:true,
 +
  configurable:true})
 +
</pre>
 +
 +
En a tenermos ahora un objeto con un atributo x que vale 11 y un atributo doble (en realidad un setter y un getter) que devuelve el doble de x o lo convierte a la mitad
 +
 +
<pre>
 +
> a.x=22  // asignamos 22 a x
 +
22
 +
> a.doble  // su doble es 44
 +
44
 +
> a.doble=10  // hacemos que el doble sea 10 ...
 +
10
 +
> a.x    // ... por lo que x es ahora 5
 +
5
 +
</pre>
 +
 +
 +
== defineProperties ==
 +
 +
Además de Object.defineProperty() que define una propiedad, tenemos el método defineProperties que permite definir muchas de golpe. en el siguiente ejemplo
 +
 +
<pre>
 +
var a = Object.defineProperties ( {} , {
 +
  "x" : {
 +
      value : 11;
 +
      writable : true;
 +
      enumerable : false;
 +
      configurable : true;
 +
  },
 +
  "y" : {
 +
      value : 22;
 +
      writable : false;
 +
      enumerable : true;
 +
      configurable : false;
 +
  });
 +
</pre>
 +
 +
estamos definiendo un objeto con dos propiedades x e y, cada una de ellas con las opciones que aparecen en el ejemplo.
  
 
[[Categoría:javascript]]
 
[[Categoría:javascript]]

Revisión actual del 14:33 18 nov 2012

En javascript podemos definir una clase con propiedades o atributos de esta forma

var a = {x:11, y:22}

Estas propiedades son por defecto visibles y modificables, pero tenemos formas de configurar todo esto. Vamos a ver algunas posibilidades


defineProperty()

La clase Object de javascript tiene un método defineProperty() que nos permite definir propiedades en otras clases, de forma similar a como definirmo x e y en el ejemplo anterior. La ventaja de defineProperty() es que nos permite configurar esa propiedad con cuatro posibles características:

  • value es el valor que queremos que tenga, 11 y 22 en el ejemplo anterior
  • writable puede ser true o false y nos indica si esa propiedad admite que se cambie su valor o no.
  • enumearable puede ser true o false y nos indica si esa propiedad aparecerá en un bucle que hagamos recorriendo las propiedades de un objeto (ver más abajo).
  • configurable puede ser true o false e indica si esa propiedad puede ser reconfigurada o no.

Object.defineProperty() admite tres parámetros, el objeto al que queremos añadir/modificar la propiedad, el nombre de la propiedad y las opciones que queremos ponerle/modificarle. Devuelve el objeto modificado, así que serían posibles estas llamadas

// Si estamos creando un objeto nuevo
var a = Object.defineProperty({}, "x", { value:11, writable:true, enumerable:true, configurable:true});

// Si el objeto ya está definido
var a = {};
Object.defineProperty(a, "x", { value:11, writable:true, enumerable:true, configurable:true});

Un detalle a tener en cuenta. Si la propiedad es nueva, los valores por defecto para cada opción son false, por lo que si no rellenamos alguna, será false. En el siguiente caso por ejemplo

var a = Object.defineProperty({}, "x", {value:11});

la propiedad x no será writable, no será enumerable y no será configurable. Si la propiedad ya existe, entonces las opcoines que no pongamos no se modificarán y permanecerán como ya las tuviera la propiedad. Por ejemplo, si hacemos

var a = {x:11};   // es writable, enumerable y configurable por defecto al definirla asi
Object.setProperty(a, "x", {writable:false});  // Ahora es no writable, pero sigue siendo enumerable y configurable.

value

Si tenemos una objeto a, podemos definirle una propiedad y darle un valor de esta forma

var a = {};
Object.defineProperty (a, "x", {value:11});
// ahora a.x vale 11

Como comentábamos antes, al no poner el resto de opciones, esta a.x es no writable, no enumerable y no configurable.


writable

Si definimos así la propiedad

var a = Object.defineProperty({}, "x", {value:11, writable:false});

La propiedad vale 11 y no se puede modificar. Si hacemos

a.x=22;

no dará error, pero a.x seguirá valiendo 11. Un detalle a tener en cuenta es que si la propiedad no es writable, pero sí es configurable, podemos cambiar su valor a través de defineProperty. Por ejemplo

var a = Object.defineProperty({}, "x", {value:11, writable:false, configurable:true});
Object.defineProperty(a, "x", {value:22});  // Esto cambia el valor aunque sea no writable. Ahora x.a vale 22


enumerable

Si definimos un objeto así

var a = {x:11, y:22};

podemos hacer un bucle para recorrer cada una de sus propiedades de esta forma

for ( propiedad in a ) {
   console.log (propiedad);  // Va escribiendo cada propiedad
}
// Esto saca en pantalla
// x
// y

Pues bien, si hacemos que una propiedad sea no enumerable, no aparecera al recorrerla con este tipo de bucle

Object.defineProperty (a, "x", {enumerable:false});
for ( propiedad in a ) {
   console.log (propiedad);  // Va escribiendo cada propiedad
}
// Esto saca en pantalla solo la y
// y


configurable

Esta es la opción que nos indica si vamos a poder usar el defineProperty() más adelante otra vez para cambiar algo o no. Si no es configurable, no podemos volver a cambiar nada, excepto hacer cambiar writable true por false. Por ejemplo, si hacemos

var a = {x:1};
Object.defineProperty(a, "x", {configurable:false});

a partir de aquí obtenemos error con cualquiera de las siguientes

Object.defineProperty(a, "x", {configurable:true});
Object.defineProperty(a, "x", {writable:true});
Object.defineProperty(a, "x", {value:2});
// Dan error "TypeError: Cannot redefine property: x"

setters y getters

A la hora de definir una propiedad con defineProperty(), en vez de indicar las opciones value y writable, podemos indicar las opciones get y set, pasando una función a esas opciones. Cuando intentemos acceder para leer la propiedad, se ejecutará la función get, cuando lo intentemos en modo escritura, se ejecutará la opción set. En el siguiente ejemplo

var a = Object.defineProperty ({}, "x", {
   get : function() {return Math.random();}, 
   set : function(valor) {console.log('me pasan '+valor)}, 
   enumerable:true, 
   configurable:true})

Si intentamos acceder a a.x para leer, obtendremos cada vez un número aleatorio

> a.x
0.28053418290801346

Si estamos con algún debugger de javascript con console como el de google chrome, cada vez que intenemos fijar un valor a a.x se sacará por pantalla un texto indicándolo, pero no se guardará nada.

> a.x=33
me pasan 33

Esto puede tener en algún momento dado alguna utilidad, pero su verdadera utilida es cuando a través de estos métodos set y get accedermos y modificamos otros atributos de la clase. Por ejemplo, podemos tener un atributo x y un método getter/setter doble, de forma que nos devuelva el doble de x o haga que x sea la mitad

var a = Object.defineProperty ({x:11}, "doble", {
   get : function() {return this.x*2;}, 
   set : function(valor) {this.x=valor/2}, 
   enumerable:true, 
   configurable:true})

En a tenermos ahora un objeto con un atributo x que vale 11 y un atributo doble (en realidad un setter y un getter) que devuelve el doble de x o lo convierte a la mitad

> a.x=22  // asignamos 22 a x
22
> a.doble   // su doble es 44
44
> a.doble=10   // hacemos que el doble sea 10 ...
10
> a.x    // ... por lo que x es ahora 5
5


defineProperties

Además de Object.defineProperty() que define una propiedad, tenemos el método defineProperties que permite definir muchas de golpe. en el siguiente ejemplo

var a = Object.defineProperties ( {} , {
   "x" : {
      value : 11;
      writable : true;
      enumerable : false;
      configurable : true;
   },
   "y" : {
      value : 22;
      writable : false;
      enumerable : true;
      configurable : false;
   });

estamos definiendo un objeto con dos propiedades x e y, cada una de ellas con las opciones que aparecen en el ejemplo.