Desde 2015 con la publicación del estándar ES6, Javascript ha recibido actualizaciones a un ritmo vertiginoso. ¿El resultado? JS es ahora uno de los lenguajes de programación más modernos y versátiles.
Las prácticas arrow functions, las técnicas de destructuring, o los operadores async / await son algunas de las novedades que se incorporaron hasta 2017.
Javascript ES2018
En este artículo voy a detallarte las novedades más interesantes de Javascript, incorporadas en 2018.
1 – Asignación por destructuring en Objetos
ES6 incorporaba el spread operator y los parámetros rest para hacer asignaciones por destructuring con Arrays.
Esto permitía 2 cosas:
- Asignar un subarray de elementos a una única variable
- Y descomponer un array en valores individuales.
Funcionaba así:
// Rest elements for array destructuring assignment:
const primes = [2, 3, 5, 7, 11];
const [first, second, ...rest] = primes;
console.log(first); // 2
console.log(second); // 3
console.log(rest); // [5, 7, 11]
// Spread elements for array literals:
const primes2 = [first, second, ...rest];
console.log(primes2); // [2, 3, 5, 7, 11]
Pues bien, desde 2018, se pueden aplicar los mismos operadores de forma análoga a los objetos. Así:
// Rest properties for object destructuring assignment:
const person = {
firstName: 'Peter',
lastName: 'Parker',
age: 26,
}
const { age, ...name } = person;
console.log(age); // 26
console.log(name); // {firstName: 'Peter', lastName: 'Parker'}
// Spread properties for object literals:
const person2 = { age, ...name };
console.log(person2);
// {age: 26, firstName: "Peter", lastName: "Parker"}
¿Y de qué sirve esto?
Aquí tienes algunas situaciones en las que te va a ser útil:
- Clonación de objetos:
Es una forma bastante más simple de clonar objetos planos que su alternativa (Object.assign({})
).
Ejemplo:
// Shallow-clone an object:
const data = { x: 42, y: 27, label: 'Treasure' };
// Antes:
const clone1 = Object.assign({}, data);
// Ahora:
const clone2 = { ...data };
- Merge de objetos:
Del mismo modo, te facilita la fusión entre 2 objetos
Ejemplo:
// Merge two objects:
const defaultSettings = { logWarnings: false, logErrors: false };
const userSettings = { logErrors: true };
// Antes
const settings1 = Object.assign({}, defaultSettings, userSettings);
// Ahora
const settings2 = { ...defaultSettings, ...userSettings };
// En ambos casos el resultado es
// { logWarnings: false, logErrors: true }
- Deshacerte de parte de un objeto:
A veces necesitas una versión «reducida» de un objeto, porque no te interesa exponer alguna propiedad.
Esto es extremadamente simple ahora:
const person = {
name: 'Peter',
age: 26,
gender: 'Male',
email: 'private@email.com',
address: 'private address 25, 08180, Somewhere.'
}
const { email, address, ...simplePerson } = person;
console.log(simplePerson); //{name: "Peter", age: 26, gender: "Male"}
2 – finally en Promises
Otra incorporación de ES6 fueron las Promises: Un mecanismo para ejecutar tareas asíncronas, y llamar una función de callback en caso de éxito (resolve) o error (reject).
Pues bien, desde 2018 las Promises te permiten llamar a una función de callback al completarse (independientemente del resultado). A continuación te dejo un ejemplo claro de uso:
const fetchAndDisplay = ({ url, element }) => {
showLoadingSpinner();
fetch(url)
.then((response) => response.text())
.then((text) => {
element.textContent = text;
})
.catch((error) => {
element.textContent = error.message;
})
.finally(() => {
hideLoadingSpinner();
});
};
3 – Iteradores asíncronos
Un iterador es un contenedor de elementos que se puede recorrer sin conocer su arquitectura, solo llamando a su método next()
.
En Javascript, existían los iteradores síncronos, donde este método devolvía dos valores:
- value con el elemento actual del contenedor
- y done indicando si el iterador ha finalizado o no.
Supongamos un iterador que contiene el array [1,2,3]
. Obtendríamos sus valores así:
syncIterator.next();
//{value:1, done:false}
syncIterator.next();
//{value:2, done:false}
syncIterator.next();
//{value:3, done:false}
syncIterator.next();
//{value:undefined, done:true}
Además, puedes usar for..of
para iterarlo (devuelve directamente el valor de cada iteración y finaliza internamente cuando done
es true
):
for (let value of syncIterator) {
console.log(value);
} // output: 1, 2, 3
Desde 2018, Javascript acepta también iteradores que devuelven valores asíncronos. Cada llamada a next
, en este caso, lo que devuelve es una Promise, así que para capturar el siguiente valor de la iteración, lo harías así:
asyncIterator.next().then(({ value, done }) => /* ...do something with value and done... */);
Buclando sobre Iteradores asíncronos
Junto con los iteradores asíncronos, se ha incorporado también la sintaxis for-await-of
para recorrerlos.
Imagina un iterador que lee un archivo (de forma asíncrona como es habitual) línea a línea. Podríamos recorrer y printar todas las líneas, así:
for await (const line of readLines(filePath)) {
console.log(line);
}
4 – Mejoras en las expresiones regulares
Se han añadido varias mejoras al sistema de expresiones regulares de Javascript. Entre otras cosas…
Named capture groups
Ahora se pueden identificar grupos de captura a través de nombres, lo que facilita su lectura. Por ejemplo:
let re = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/u;
let result = re.exec('2015-01-02');
// result.groups.year === '2015';
// result.groups.month === '01';
// result.groups.day === '02';
Lookbehind assertions
Hasta el momento, las expresiones regulares de JS tenían un mecanismo para comprobar si una expresión iba seguida de un determinado patrón (lookahead: ?=pattern
).
Por ejemplo, la siguiente expresión : /^([0-9]{2})(?=H)/
daría positivo para números de 2 cifras seguidos de la letra H (sin incluirla en el match).
const regex = /^([0-9]{2})(?=H)/;
regex.exec('12H');
// encuentra 12 como match.
Lo que no había es un mecanismo para comprobar si la expresión estaba precedida de un determinado patrón. Esto es lo que llamamos lookbehind (?<=pattern
). Para comprobar si una cantidad monetaria esta precedida por el símbolo del €, podríamos hacerlo así:
const regex = /(?<=€)([0-9])+/;
regex.test('€2000');
// encuentra 2000 como coincidencia
Reflexiones personales
Como ves, JS no para de evolucionar. Cada año se incorporan novedades para facilitar el trabajo de los desarrolladores y adaptar el lenguaje a las necesidades que se detectan. En próximos posts te contaré las novedades que se han añadido este año 2019, y lo que se espera para 2020.
¿Te ha gustado este artículo? No te cortes, déjame un comentario y ayúdame a compartirlo 😉