3 Features de JavaScript que aprendí fuera de la escuela

Share on facebook
Share on twitter
Share on linkedin

No me malentiendan, aprendí mucho en la facultad. La materia que nos mostró algo de JavaScript (Desarrollo de Aplicaciones Web) fue una de la que muchos compañeros se enamoraron, sin ella no sabría jugar con el DOM, no sabría qué es Ajax, fundamentos de php, etc.

Es de esperar que en un curso no intensivo de 6 meses haya poco tiempo para adentrarse en detalles y truquitos de cada lenguaje. El lado positivo es que todavía se cuenta con el resto de una vida para aprenderlos. A continuación mencionaré algunos features que aprendí en el trabajo y me ayudaron mucho.

1. No es necesario sumar cadenas

Bueno, este apartado será corto. Dudaba si designarle todo un subtítulo a las Template literals (o template strings), pero no podía dejar de lado a uno de mis trucos favoritos de ES6+. Estas dos líneas son equivalentes:

'Bienvenido ' + nombre + ', son las ' + (new Date().getHours() + 1) + ' horas';

`Bienvenido ${nombre}, son las ${new Date().getHours() + 1} horas`;

Al usar acentos graves ` se pueden agregar expresiones dentro de un ${}, haciendo más bonita la concatenación de cadenas y expresiones.

2. ¿A dónde apuntan esas flechas?

La primera vez que vi un símbolo de “igual” junto al “mayor que” creí que era un operador lógico. Leía y releía los => pero nada cobraba sentido. Afortunadamente encontré un video explicando que eso es una función flecha, y desde ese entonces no dejo de usar tan conveniente notación

Sintaxis

// Función anónima
function(<argumentos>) { <cuerpo> }

// Función flecha
(<argumentos>) => { <cuerpo> }

La sintaxis de una función flecha es muy parecida a la de una función anónima. A la izquierda de la flecha se declaran los argumentos, y a su derecha el cuerpo. Sin embargo, la función flecha tiene un poco más de azúcar sintáctica:

  • Paréntesis opcionales: Si la función flecha recibe un solo argumento que no se desestructura, se pueden omitir los paréntesis del argumento. Es decir, estas dos líneas serían equivalentes:
    (<argumento>) => { <cuerpo> }
    <argumento> => { <cuerpo> }
  • Retorno implícito: Si el cuerpo de la función flecha solo consta de retornar una expresión, eliminar los corchetes hará que el return sea implícito. Es decir, estas dos líneas serían equivalentes:
    (<argumentos>) => { return <expresión> }
    (<argumentos>) => <expresión>

Por ejemplo: se tiene un arreglo con números y se desea saber cuáles son mayores a 3. Usemos al método Array.prototype.filter(), que crea un nuevo array con todos los elementos que cumplan la condición implementada por la función dada (Copypasteado de MDN).

const numbers = [5, 8, 1, 0, 10, -4];

const usingFunction = numbers.filter(function(number){
  return number > 3;
});

const usingArrow = numbers.filter(number => number > 3);

// Tanto usingFunction como usingArrow serán [5, 8, 10]

Más que un sustituto de function

Voy a plantear un problema antes de decir dónde entran las =>. Dentro de un método de un objeto se quiere llamar a una promesa y se desea almacenar, en el mismo objeto, algún valor que diga si la promesa se cumplió o no. Por motivos de simplicidad, la promesa en cuestión se llamará somePromise y no diremos qué hace.

const obj = {
  promiseSuccessful: false,
  someMethod() {
    somePromise().then(function() {
      this.promiseSuccessful = true;
    });
  }
};
obj.someMethod();

Uno podría pensar que el valor de obj.promiseSuccessful sea true si la promesa es exitosa, pero la manera en que this funciona hace que este no sea el caso, porque el this dentro de la función anónima apunta a un this global en lugar de a obj.

Conozco dos soluciones. Una es no usar this dentro de la función anónima.

// ...
  someMethod() {
    const self = this;
    somePromise().then(function() {
      self.promiseSuccessful = true;
    });
  }
// ...

La otra solución es usar una función flecha. La característica más distintiva de este tipo de funciones es que su this apunta al mismo this donde fue declarada.

// ...
  someMethod() {
    somePromise().then(() => {
      this.promiseSuccessful = true;
    });
  }
// ...

En este ejemplo, la función flecha fue declarada dentro de someMethod. Como el this dentro de someMethod apunta a obj, el this dentro de la función flecha también apuntará a obj.

¿Cuándo no usarlas?

Si al crear un objeto se usan funciones flecha para declarar sus métodos, el this de tales métodos no va a apuntar al objeto, sino al this del lugar donde se creó. Por ejemplo: las siguientes líneas tienen un problema similar al que teníamos inicialmente.

const obj = {
  promiseSuccessful: false,
  someMethod: () => {
    somePromise().then(() => {
      this.promiseSuccessful = true;
    });
  }
};

Debido al uso de => al declarar someMethod, el this hace referencia al lugar donde se creó obj, no al mismo obj.

JavaScript functions be like "This is complicated".
Wikimedia commons

3. Expandiendo la idea de clave-valor

Cuando empecé a programar en JavaScript me llamó mucho la atención que los objetos aquí no son instancias de una clase. Los veía como sacos que permiten agregar y quitar cosas a lo desgraciado y sin privacidad. Sigo viéndolos de esa forma, pero ahora sé que pueden tener un par de reglas más.

Este apartado no es para hablar de los objetos en sí, sino una parte fundamental de ellos: las propiedades.

const persona = {
  nombre: 'Esteban Dido'
};

El objeto anterior representa a una persona y su nombre. No nos fijaremos en el objeto en sí, sino de su propiedad “nombre. Tal propiedad tiene las siguientes características:

  • Guarda un valor (value). En este caso, el valor es ‘Esteban Dido’.
  • Se le puede asignar otro valor (writable): Más adelante, alguien podría cambiarle su nombre.
  • Se puede configurar (configurable): Nada impide que más adelante alguien elimine nombre o modifique sus descriptores (en breve diremos qué es eso).
  • Aparece al enumerar las propiedades (enumerable): Esto quiere decir que los métodos que usen las propiedades de persona, como JSON.stringify() u Object.keys(), también incluyen a “nombre”.

Estas características y un par más, son los descriptores de una propiedad. La forma de modificar los descriptores de una propiedad es con Object.defineProperty(), un método muy especial que recibe 3 argumentos:

  • El objeto al cual se le va a agregar o configurar la propiedad.
  • La clave de la propiedad.
  • Un objeto con sus descriptores.

Si quisiéramos definir la propiedad “nombre” de manera explícita, haríamos lo siguiente:

const persona = {};
Object.defineProperty(
  persona, // Objeto a modificar
  'nombre', // Clave de la propiedad
  { // Descriptores
    value: 'Esteban Dido',
    writable: true,
    configurable: true,
    enumerable: true
  }
);

Propiedades semi ocultas

Lo que me inspiró a hablar de descriptores en este artículo fue enumerable, pues me parece el más interesante de todos.

Si quiero que persona tenga la propiedad secreto pero no quiero que esa propiedad aparezca en el resultado de JSON.stringify(persona), puedo definir secreto como no enumerable.

const persona = {
  nombre: 'Esteban Dido'
};
Object.defineProperty(persona, 'secreto', {
  value: 'Robo chicles del Oxxo',
  enumerable: false
});
JSON.stringify(persona); // '{"nombre":"Esteban Dido"}'
persona.secreto; // 'Robo chicles del Oxxo'

Anécdota: En una ocasión quería guardar (en formato JSON) un arreglo de objetos, pero cierta dependencia requería que esos objetos tengan un valor que no me interesaba almacenar. El mayor problema era que los objetos tenían estructuras diferentes, así que no podía simplemente eliminar ese valor. Después de no poder implementar una solución complicada le pedí ayuda a un amigo, quien me habló de Object.defineProperty(). No podía creer que sea posible configurar una propiedad.

Para terminar…

Hay muchos conceptos y features que Programadores Senior deben dominar, y estoy seguro de no conocer ni un cuarto. Saber usar un lenguaje no lo es todo, también hay que estar enterado de cosas como modularidad, buenas prácticas, principios SOLID, etc. A veces me siento un poco abrumado por tantos conceptos, pero una parte importante de ser programador es estar aprendiendo siempre, pues es natural no saber todo. Para concluir, no puedo sino alentarles a seguir ampliando su base de conocimiento.

Share on facebook
Share on twitter
Share on linkedin

No hay comentarios

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

¡Conozcámonos mejor!

Te haremos llegar las novedades de SoldAI, ofertas exclusivas, notificaciones, y mucho más.

¡Deja tu correo, tenemos mucho que contarte!