Getters y Setters en JavaScript

Mosh Hamedani

Follow

Dic 29, 2019 – 5 min read

.

El concepto de getters y setters es bastante común entre los lenguajes populares en uso hoy en día. Alguna vez has necesitado asegurarte de que una determinada acción se realice siempre antes o después de asignar algún valor a la propiedad de un objeto? Esto es posible con los setters. También puedes realizar cualquier tipo de procesamiento al recuperar el valor de una propiedad mediante el uso de getters (por ejemplo, formatear). Una forma de implementar getters y setters es utilizar métodos, como se hace en Java. Sin embargo, desde ES5, disponemos de una alternativa mucho más elegante y práctica utilizando la sintaxis get y set. Bien, ¡comencemos!

En JavaScript, los objetos son colecciones de propiedades y probablemente los hayas utilizado para almacenar datos antes. Una propiedad es simplemente un par clave-valor. Aquí hay un ejemplo:

const options = {
timeout: 5000,
retries: 3,
ip: '192.168.1.20',
port: 4001,
};

Las propiedades de un objeto se pueden establecer y leer fácilmente, así:

artist.name = 'Carice Anouk van Houten';console.log(artist.name); //=> "Carice Anouk van Houten"

De nuevo, esto no es nada nuevo si ya tienes algo de experiencia con JavaScript. Para hacer una distinción entre estas propiedades regulares y el otro tipo que veremos en este artículo, podemos llamar a las primeras «propiedades de datos».

Getters y setters: la forma antigua

Antes de ES5, la única forma que teníamos de implementar getters y setters era usando métodos regulares. Como en el ejemplo siguiente:

He mantenido la palabra clave function en el ejemplo anterior para dejar claro que aquí no hay magia. Sólo métodos normales. Podríamos haber conseguido el mismo efecto utilizando la sintaxis de definición de métodos de ES2015, que es más corta y algo más elegante:

const config = {
_port: 4001,
setPort(port) {
// ...
},
getPort() {
// ...
},
};

El uso de este tipo de getters y setters es bastante sencillo:

config.setPort(8080);
console.log(config.getPort()); //=> 8080

Incrementar un valor se haría así:

item.setQuantity(item.getQuantity() + 1);

Lo cual parece realmente verboso si se compara con incrementar una propiedad directamente:

item.quantity += 1;
// Or even simpler...
item.quantity++;

Getters y setters: ¿por qué?

En lenguajes OO como Java, C++ o C#, es posible exponer los miembros de una clase a diferentes niveles utilizando modificadores de acceso (como public, protected y private). Esto sirve para implementar un importante concepto de la POO llamado ocultación de datos.

Un uso muy común de los getters y setters en estos lenguajes es exponer miembros de una clase de forma segura. Por ejemplo, puedes implementar sólo un getter para asegurarte de que un miembro privado nunca será modificado desde fuera de la clase. Un setter, a su vez, puede utilizarse para validar los valores suministrados y preservar la integridad de las instancias de esa clase.

¿Y en JavaScript?

En JavaScript, las cosas son un poco diferentes. En el momento de escribir este artículo, no hay modificadores de acceso en JS. Actualmente, la mejor opción que tenemos es usar símbolos, que nos dan cierto nivel de privacidad cuando se usan como claves. Sin embargo, a algunas personas no les gustan. Sobre todo porque es fácil romper esta privacidad usando reflection.

No considero que esto sea un problema real ya que los lenguajes que tienen reflection suelen permitir a los programadores romper la encapsulación de alguna manera. El problema que veo en los símbolos es que no son tan prácticos de usar como lo sería un simple accesor privado. La buena noticia es que una propuesta de EcmaScript que incluye campos privados ya está en la fase 3. Y serán inmunes a cualquier tipo de reflexión.

En el ejemplo de la sección anterior, no usamos símbolos ni ningún otro truco para simular un miembro privado. La propiedad _port no tiene nada especial per se. Es simplemente una propiedad de datos normal y, como tal, se puede establecer o leer directamente, saltándose por completo el getter y el setter que hemos creado.

Como explicar los símbolos y otras técnicas de encapsulación no es el objetivo de este artículo, no implemento las propiedades privadas en sus ejemplos de código. Sólo hay que tener en cuenta que los getters y setters se utilizan comúnmente (pero no siempre) para proporcionar acceso a los miembros encapsulados. Por último, observe el guión bajo que precede al nombre de la propiedad _port. Es una convención de facto entre los desarrolladores de JS, que indica que una determinada propiedad es privada y no debe ser accedida desde fuera de la clase en la que está definida.

Getters y setters: la nueva forma con las propiedades accessor

Las propiedades accessor son la forma moderna de definir getters y setters. Cuando se trata de su definición, no son tan diferentes de nuestro ejemplo anterior, pero es su uso lo que es realmente diferente. En primer lugar, vamos a adaptar nuestro código para utilizar propiedades accesorias:

Como puedes ver, sólo dos cosas han cambiado en este ejemplo:

  • En lugar de tener métodos setPort y getPort. Utilizamos la sintaxis set y get junto con un único nombre para la propiedad («port«, en este ejemplo)
  • No necesitamos la palabra clave function aquí. De hecho, si intentas usarla, obtendrás un SyntaxError.

¿Cómo usar las propiedades accesorias?

Si la definición de una propiedad accesoria es bastante similar a cómo creamos los getters y setters de la vieja escuela, su uso no tiene ninguna diferencia visible de cómo usamos las propiedades de datos regulares:

config.port = 8080;
console.log(config.port); //=> 8080

Y así es como se ve una expresión de incremento:

timer.seconds += 1;

Sí. Es así de sencillo. =)

Conclusión

  • Los objetos son colecciones de propiedades
  • Una propiedad normal es sólo un par clave-valor y puede llamarse «propiedad de datos»
  • Puedes implementar getters y setters como métodos normales. Esta es la forma «de la vieja escuela» de hacerlo en JavaScript.
  • Los getters y setters se utilizan normalmente para proporcionar acceso a los miembros privados de una clase.
  • Las propiedades accesorias pueden comportarse exactamente como los getters y setters basados en métodos normales, pero su uso está diseñado para que parezcan propiedades de datos.

¿Quieres dominar JavaScript? Te recomiendo los cursos de JavaScript de Mosh.

Y si te ha gustado este artículo, ¡compártelo también!

Deja una respuesta

Tu dirección de correo electrónico no será publicada.