Lo nuevo que trae ES2020

En este blog amamos JavaScript y es por eso que he dedicado toda una miniserie a los features que han sido introducidos desde ES6 en adelante.

En este blog amamos JavaScript

El día de hoy es hora de hablar sobre las nuevas características del lenguaje adoptadas en este año. Algunas son interesantes, asombrosas, otras son balances pequeños pero que se aprecian.

Veamos esta lista, mezclando entre más y menos interesantes.

El tema de hoy fue recomendado por un suscriptor de la newsletter.

BigInt

JavaScript y los números no se llevan bien. Por eso hay tantas librerías que se encargan de hacer las matemáticas pesadas en JavaScript. Los BigInts pretenden solucionar esto.

El límite teórico de los valores enteros en JavaScript es 9007199254740991 (obtenido con Number.MAX_SAFE_INTEGER) cualquier número que sumemos o restemos de aquí es tan confiable como las promesas de tu ex. Aquí es donde entra el nuevo tipo de dato BigInt.

Agregando una n al final de nuestros valores enteros los convertimos de Int a BigInt.

const int = 9007199254740992;
const bigint = 9007199254740992n; // Mismo número pero convertido en BigInt
console.log(int === int + 1); // true 😳
console.log(bigint === bigint + 1n); // false 😌

Dynamic Imports

Bueno, esto ha estado hace un tiempo ya, gracias a Babel y webpack (y el hermoso parcel), pero ahora es algo oficial en el lenguaje que podremos ver a los navegadores (que aún no lo tienen) implementando en el futuro cercano.

Sin rodeos y para quien no conocía lo de importar módulos de forma dinámica, es una forma de importar los módulos que queremos solo en las situaciones que los necesitamos. En un ejemplo (súper hipotético) de una calculadora súper científica en la que mayormente solo se hacen divisiones y no sumas, podríamos, gracias a los dynamic imports, tener algo como esto.

import divide from "./operations/division"; // Se importa siempre

async function Calculate(a, b, op) {
  // ... Cosas científicas
  if (op === "sum") {
    const sum = await import("./operations/sum"); // Se importa solo cuando se hace suma
    sum(a, b);
  }
}

¿Esto no importaría el módulo cada vez que sumemos? Buena pregunta, pero la respuesta es no. Primero se revisa si el módulo ya se había importado antes, de ser así se utiliza el que está en caché y así no se hacen múltiples peticiones a la red. La forma de saber si el módulo ya ha sido importado o no es a través de la metadata del módulo.

Module metadata

Me quedaré con la versión en inglés de los nombres ya que traducir algo que vamos a usar siempre en inglés no vale la pena.

Directo al punto. Ahora los módulos al importarlos exponen un key meta que había estado vacío antes. Ahora contienen información como la url del archivo que tiene el módulo entre otras cosas.

Module namespace export

Para cerrar el apartado sobre los módulos tenemos este otro pequeño pero muy apreciado. Y es que JavaScript nos permitía importar todo el contenido de un módulo usando el asterisco (*) y asignándole un nombre, pero no podíamos hacer lo mismo para exportarlo; debíamos exportar directamente parte por parte o agregar un export object especificando lo que se exportaba. Ahora podemos hacer lo siguiente:

// Lo que siempre hemos podido hacer
import * as operations from "./operations";

// Como se debía exportar antes
import * as sum from "./sum";
export { sum };

// Como se puede exportar ahora
export * as sum from "./sum";

Nullish Coalescing

Este es una de mis características favoritas y más esperadas de esta iteración de JavaScript. El nuevo operador de doble interrogación ?? nos permite verificar que el valor a la izquierda es realmente null || undefined en lugar de verificar si es un valor falsy .

En JavaScript los valores falsy son aquellos que el lenguaje trata como false aunque no lo sean. Esto incluyen un string vacío, el número 0, null, undefined, NaN y por supuesto el booleano false.

Veamos un ejemplo de como esto nos puede ayudar a simplificar nuestro código en ciertos escenarios.

const showValue = val => console.log(`El valor es ${val || "NO VALOR"}`);

// El valor es NO VALOR
showValue();
showValue(0);
showValue(false);
showValue("");
showValue(NaN);

// El siguiente código si funciona, pero el syntax highlighter todavía no conoce esta sintaxis.

const showValueIfNotNull = val => console.log(`El valor es ${val ?? "NO VALOR"}`);

// Una forma de hacer esto antes era
const oldShowValueIfNotNull = val => {
  // Revisar explicitamente por valores null o undefined
  const value = val === null || val === undefined ? "NO VALOR" : val;
  console.log(`El valor es ${value}`);
};

showValueIfNotNull(); // El valor es NO VALOR
showValueIfNotNull(0); // El valor es 0
showValueIfNotNull(false); // El valor es NO false
showValueIfNotNull(""); // El valor es
showValueIfNotNull(NaN); // El valor es NaN

Promise.allSettled

Las promesas han venido para quedarse. Y es que son la mejor forma de crear código asíncrono en JavaScript.

Aún así, cuando empezamos a implementarlas solo podíamos hacerlo de una a la vez y había que hacer magia si queríamos ejecutar alguna función independientemente de como se resolviera la función. Para correr una función cuando termine la promesa, independientemente del resultado, tenemos el método Promise.finally.

Para ejecutar varias promesas a la vez hay varios métodos: Promise.race Promise.all y ahora Promise.allSettled que a diferencia de Promise.all, que se completa cuando todas se completan y falla si al menos una falla, este se completa cuando todas terminan independientemente si fallaron o no.

const promises = [Promise.reject(100), Promise.resolve("Juanito"), Promise.reject(new Error("E"))];

Promise.allSettled(promises).then(r => {
  console.log(r.map(p => p.status)); // ['rejected'', 'fullfilled', 'rejected']
});

// Comparada con Promise.all
Promise.all(promises)
  .then(_ => {
    /* Esto nunca se llama */
  })
  .catch(e => console.log(e)); // 100 -> al primer reject se detiene

Optional Chaining

Este, de mis favoritos también y lo llegué a mencionar en el post de ES6 y más allá parte 2 (en la parte de más allá). Di adiós a las pirámides de código con un montón de ifs anidados para verificar si una propiedad existe. Con el optional chaining operator (.?) puedes acceder a propiedades anidadas sin preocuparte por errores.

Virgin vs Chad

// The virgin property check
if (user && user.profile && user.profile.personalInfo && user.personalInfo.name) {
  console.log(user.profile.personalInfo.name);
}

// The Chad property check
console.log(user?.profile?.personalInfo?.name); //`undefined` o el nombre del usuario

Regexp y otras cosas

En este apartado incluyo otros cambios que vienen en ES2020 pero que no son tan vistosos (al menos para mi) pero que siguen siendo buenos.

Conclusión

El lenguaje de JavaScript avanza y evoluciona. Es bonito ver que ya no estamos viviendo como en los tiempos de antes en los que durábamos casi 10 años para que se agregaran cosas al lenguaje y se estandarizaran otras.

Ahora no solo se están agregando nuevos elementos y mejorando los anteriores, sino que también las plataformas como node y los navegadores (todos ellos) están adoptando rápidamente estas características desplazando cada vez más la necesidad de usar transpilers. El futuro es prometedor.

Por favor, déjame saber cuál de estas es tu característica favorita de ES2020. Si quieres no perderte nada y sugerir temas como el de hoy, te recomiendo que te suscribas a mi newsletter, es gratis y está llena de información no intrusiva relevante.

Ir al principio