EcmaScript 6

Hoy vamos a ver once características, o cualidades, o mejoras, o como le queráis llamar de JavaScript que son poco conocidas. No me enrollo más, y pasemos ¡al turrón! (buenas fechas para decirlo).

1. Cargar módulos sin librerías

De un tiempo a esta parte, es posible importar módulos en JavaScript sin necesidad de librerías externas gracias a la sentencia import . Veamos como funciona con un ejemplo sencillo:

// Fichero main.js
import("./module.js").then(function(module) {
  module.hiWorld();
}).catch(function(error) {
  console.log("Error loading module: " + error);
});

// Fichero module.js
export function hiWorld() {
	console.log("Hi world from module!!");
}

// Por consola veremos: Hi world from module!!

Si te gusta usar los await’s estás de suerte, pues puedes hacer importaciones desde una función tal que así:

// Fichero main.js
async function loadModule() {
	const module = await import("./module.js");
	module.hiWorld();
};

loadModule();

// Por consola veremos: Hi world from module!!

2. Esperar a que terminen todas las promesas

El método Promise.all() termina en cuanto una promesa de las que recibe falla. Sin embargo en ocasiones puede que nos interese esperar a que todas las promesas vayan bien o mal. Para ello podemos usar Promise.allSettled().

Como siempre veamos un ejemplo aprovechando los import que vimos antes (que devuelven una promesa):

Promise.all([import("./module.js"), import("./notexisting.js")])
	.then(function(data) {
		console.log("Esto no va a salir nunca por consola");
	}).catch(function(error) {
		console.error("Promise.all: Falla el segundo import");
	});

// La ejecución del código anterior mostrará lo siguiente por consola:
// "Promise.all: Falla el segundo import"
// Ya que la segunda promesa ha fallado.

Promise.allSettled([import("./module.js"), import("./notexisting.js")])
	.then(function(data) {
		console.log("Promise.allSettled", data);
	}).catch(function(error) {
		console.error("Como sólo hay un error no se mostrará este mensaje");
	});

// La ejecución del código anterior mostrará lo siguiente por consola:
// Promise.allSettled,
// [
//   {status: 'fulfilled', value: Module},
//   {status: 'rejected', reason: TypeError: Failed to fetch dynamically imported module: http://jafs.es/notexisting.js}
// ]

Podemos ver como con allSettled(), recibimos un array de resultados de promesa como argumento de la función utilizada en then. Así podremos saber que llamadas han funcionado y las que han fallado.

Una buen caso de uso para este ejemplo, se da en el caso de que necesitemos hacer varias llamadas REST de forma simultánea. Así aunque una falle, podremos saber el resultado de las demás.

Un último apunte a destacar de allSettled(), y es que aunque fallen todas las promesas, siempre pasará por el camino then. En nuestro ejemplo lo pusimos a modo ilustrativo para ver que por ahí no pasa 😉.

3. Dejar de esperar varias promesas en cuanto termine una

En esta ocasión, si lo que queremos es que se termine la espera en cuanto se resuelva una promesa de varias, lo que usaremos es any() . Con ella, para que el código pase por el catch, deberán fallar todas las promesas.

Promise.any([import("./module.js"), import("./alsoExisting.js")])
	.then(function(data) {
		console.log("Promise.any", data);
	}).catch(function(error) {
		console.error("Si existen los dos módulos no saldrá este mensaje");
	});

// La ejecución del código anterior mostrará lo siguiente por consola:
// Promise.any, Module { hiWorld: (...) }

Promise.any([import("./notExisting1.js"), import("./notExisting2.js")])
	.then(function(data) {
		console.log("Promise.any", data);
	}).catch(function(error) {
		console.error("Como no existen los dos módulos ahora si sale este mensaje");
	});

// La ejecución del código anterior mostrará lo siguiente por consola:
// Como no existen los dos módulos ahora si sale este mensaje

4. Hay un this global, pero de verdad de la buena

Toda la gente que nos hemos peleado con JavaScript, hemos visto que dependiendo del entorno en que ejecutemos nuestros scripts, si llamamos a this a secas fuera de todo ámbito, el objeto global cambia. En los navegadores es window, en Node.js es global y en los WebWorker es self.

Pues a partir de ahora, si queréis hacer algo más unificado, tan sólo tendréis que llamar a globalThis . Esta palabra clave tendrá la instancia del objeto global que corresponda sin depender del entorno.

5. Acceder a atributos que pueden ser nulos o indefinidos

A esta técnica se le llama Optional chaining. Y para ello usamos el operador ?. . Con esto ya no tendremos errores si un atributo no existe:

const vehiculo = {
  ruedas: 4,
  motor: false,
  modelo: null
};

vehiculo.alas?.tipo;    // undefined en lugar de error
vehiculo.modelo?.marca; // undefined en lugar de error

vehiculo.alas.tipo;    // Uncaught TypeError: Cannot read properties of undefined (reading 'tipo')
vehiculo.modelo.marca; // Uncaught TypeError: Cannot read properties of null (reading 'tipo')

El operador provoca un “cortocircuito” cuando la propiedad a su izquierda no existe, o tiene valor null. Devolviendo automáticamente el valor undefined, en lugar de un error como ocurre si quitamos este nuevo operador.

6. “Aplanar” arrays

Otra cosita genial, es que ahora podemos pasar un array de varias dimensiones a sólo una, gracias el método flat() . En el código siguiente, pongo varios saltos de línea para que os quede más claro cada array de ejemplo:

let arr = [
  [1, 2],
  [3, 4, 5]
];
arr.flat();  // Ahora tendremos: [1, 2, 3, 4, 5]

arr = [
  [1, 2],
  [3, 4, 5],
  [
    [6],
    [7]
  ]
];

arr.flat();  // Como hay un tercer nivel, el 6 y el 7 no se aplanan: [1, 2, 3, 4, 5, Array(1), Array(1)]
arr.flat(2); // Ahora le hemos dicho que profundice un nivel más: [1, 2, 3, 4, 5, 6, 7]

Si no pasamos parámetros, por defecto, sólo "aplana" la segunda dimensión (equivaldría a poner 1 como parámetro), pero le podemos pasar el número de dimensiones extra a comprobar.

7. El mágico operador ??

Este nuevo amiguito con nombre y apellidos, se llama nullish coalescing operator y viene representado por ?? . En primera instancia puede parecer que su uso es como el operador ||, que nos devuelve el primer valor que no sea falsy, pero es mejor, ya que sólo funciona con null y undefined, devolviendo el resto de valores falsy. Mejor que lo veáis con un ejemplo:

// Con estos devuelve el primer valor
"" ?? 123;        // ""
false ?? 123;     // false
0 ?? 123;         // 0
NaN ?? 123;       // NaN

// Aquí es donde pasa a actuar el operador
null ?? 123;      // 123
undefined ?? 123; // 123

8. Operadores de asignación lógicos

El anterior operador más los ya conocidos &&|| ya se pueden utilizar en la asignación de valores, en este caso, se les llama operadores de asignación lógicos :

// Operador ||=
// Cuando tiene un valor falsy se asigna el valor tras la igualdad
let increment = 0; 
increment ||= 12; // 0 es falsy, se asigna 12

increment = 234;  // 234 es truthy, se queda con el valor 234
increment ||= 12;

// Operador &&=
// Cuando tiene un valor truthy se asigna el valor
increment = 0;
increment &&= 123; // 0 es falsy, se queda con el valor 0

increment &&= 234;
increment = 12;   // 234 es truthy, se asigna el valor 12.

// Operador ??=
// Se asigna el valor tras la igualdad cuando la variable es null o undefined
increment = 12;
increment ??= 234; // Se queda con el valor 12

increment = null;
increment ??= 234;  // Ahora tiene el valor 234

increment = undefined;
increment ??= 234; // Ahora tiene el valor 234

Hay que destacar que con las cadenas, este tipo de operadores no funcionan como se espera (al menos con navegadores con motores Chromium y Gecko), ya que si probamos tenemos lo siguiente:

// Operador ||=
name = null;
name ||= "Juan"; // Asigna la cadena "null".

name = undefined;
name ||= "Juan";  // Asigna la cadena "undefined".

// Operador &&=
name = undefined;
name &&= "Juan";  // Funciona al contrario, se asigna el valor "Juan"

name = null;
name &&= "Juan";  // Funciona al contrario, se asigna el valor "Juan"

// Operador ??=
name = null;
name ??= "Juan"; // Asigna la cadena "null"

name = undefined;
name ??= "Juan"; // Asigna la cadena "undefined"

9. Separador numérico

Puede que manejemos cifras que son grandes en nuestra aplicación, y queda a veces enrevesado poder distinguir que cifra hay escrita si no se pone cierta atención en su lectura. Pues el nuevo separador de miles de JavaScript acude en nuestra ayuda cual Chapulín Colorado. Es tan sencillo como poner el símbolo _ para separar los miles:

// Hace más legibles números grandes como los siguientes:
345_432_534.23         // 345.432.534,23
10_343_039             // 10.343.039
12_345_677_865_320.459 // 12.345.677.865.320,459

10. Reemplazos en cadenas sin expresiones regulares

¿Cuántas veces hemos usado una expresión regular para reemplazar todas las veces que aparecía un texto en una cadena? Pues ¡el "expresionar" se va a acabar! (Aquellas personas de cierta edad entenderán el “chiste”).

Ahora las cadenas tienen un método nuevo llamado replaceAll() que hace todo el trabajo... sucio. Sólo hay que pasar el texto a reemplazar y el que queremos poner en su lugar, y hará toda la magia.

const something = "hola adios que tal hola que ase";

// Así sólo reemplazamos la primera vez que aparece "hola":
something.replace("hola", "");     // " adios que tal hola que ase"

// Lo que nos obliga a usar una expresión regular:
something.replace(/hola/g, "#");   // "# adios que tal # que ase"

// Con el nuevo método:
something.replaceAll("hola", "#"); // "# adios que tal # que ase"

11. En los arrays no todo son corchetes

Seguro que muchas veces para acceder al último elemento de un array, has jugado con ir a la posición dada por la longitud del array - 1. Ahora tenemos el método at() que con posiciones positivas funciona como los corchetes, pero al que si le pasamos posiciones negativas, comienza desde la parte de atrás del array. Veamos a nuestro amiguito en acción:

const myArray = [1, 2, 3, 4, 5];
myArray.at(2);  // => 3 | De momento aquí nada nuevo
myArray.at(-1); // => 5 | Esta es la parte buena, hemos comenzado por el final del array
myArray.at(-3); // => 3

Esto es todo por hoy, espero que a quienes no conozcáis alguna de las cosillas sobre JavaScript comentadas arriba os pueda haber ayudado; y como siempre cualquier dudilla dejadla en los comentarios 😉.

Comparte este artículo con quien quieras
Iteradores en JavaScript. Parte 2. Funciones generadoras
3 formas extra de definir constantes con TypeScript

Leave a Comment

Your email address will not be published. Required fields are marked *

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.