Hay trucos que quedan bien en una línea de código y hay trucos que cambian nuestra forma de programar.
Si tuviera que quedarme sólo con una de todas las, ya no tan nuevas, funcionalidades y sintaxis de ES6 elegiría la desestructuración de arrays y objetos sin duda alguna. Es la que una y otra vez viene a echarme una mano y me deja tomarle el brazo.
Cierto, la sintaxis es marciana y difícil de entender al principio, pero créeme, compensa el esfuerzo de convertirla en una de tus herramientas habituales.
Desestructuración de arrays
Empezamos con los arrays porque es más sencillo entender la sintaxis.
En realidad la idea es bien sencilla, tenemos un array y queremos almacenar cada uno de sus valores en una variable, para no tener que escribir cosas como nombreDeArray[2]
todo el rato. Esta situación es habitual cuando usamos una API que devuelve los datos en forma de array y no queremos usarlos de esa forma.
Así es como resolvíamos el problema antes:
function uglyAPI() { return [1, 2, 3]; }
//...
var tmp = uglyAPI();
var a = tmp[0];
var b = tmp[1];
var c = tmp[2];
Y así es como lo resolvemos ahora:
function uglyAPI() { return [1, 2, 3]; }
var [ a, b, c ] = uglyAPI();
Si ya habíamos declarado las variables:
function uglyAPI() { return [1, 2, 3]; }
//...
var a, b, c;
//...
[ a, b, c ] = uglyAPI();
Si no estamos seguros de que la API nos devuelva siempre el array (nos podría devolver undefined
o null
) y queremos evitar un error del tipo:
Uncaught TypeError: uglyAPI is not a function or its return value
is not iterable
Podemos recurrir a nuestro viejo amigo el operador de cortocircuito OR
function uglyAPI() { return [1, 2, 3]; }
var [ a, b, c ] = uglyAPI() || [];
Ahora bien, ¿que pasa si el array devuelto no siempre tiene la misma longitud?
function uglyAPI() { return [1, 2]; }
var [ a, b, c ] = uglyAPI() || [];
console.log(a, b, c) // 1 2 undefined
En este caso podemos darle valores por defecto a las variables desestructuradas:
function uglyAPI() { return [1, 2]; }
var [ a, b, c = 53 ] = uglyAPI() || [];
console.log(a, b, c) // 1 2 53
Aquí es donde yo prefiero empezar a separar en diferentes líneas las variables por legibilidad,
function uglyAPI() { return [1, 2]; }
var [
a = 3,
b = 15,
c = 53 ] = uglyAPI();
console.log(a, b, c) // 1 2 53
Aunque esto es cuestión de gustos, lo incluyo para que sepas que se puede hacer.
Por otro lado, no tenemos por qué asignar todos los valores del array si no queremos:
function uglyAPI() { return [1, 2, 3]; }
var [ a, b ] = uglyAPI();
Si queremos ignorar un valor del principio del array, o intermedio, podemos escribir la coma, y dejar el lugar de la variable vacío:
function uglyAPI() { return [1, 2, 3, 4, 5, 6, 7, 8]; }
var [,a,,,,b,c ] = uglyAPI();
console.log(a, b, c); // 2 6 7
Si no te gusta contar comas, hay una forma aun más elegante de hacer esto mismo:
function uglyAPI() { return [21, 22, 23, 24, 25, 26, 27, 28]; }
var {
1:a,
5:b,
6:c } = uglyAPI();
console.log(a, b, c); // 22 26 27
Fíjate en que he cambiado los valores del array para evitar toda posible confusión con sus índices. Presta atención a que en este caso no estoy usando corchetes, [
]
, para la desestructuración, sino llaves, {
}
.
Esto debería, quizás, darte una pista de que en este caso estamos tratando el array como un objeto, accediendo a sus valores por el nombre de sus propiedades, que son precisamente los índices del array.
Hablaré más de esta forma en la siguiente entrega que estará dedicada a los objetos. Pero me parecía apropiado incluirlo aquí porque probablemente esta sea la forma más legible de desestructurar un array.
Pero esto no acaba aquí, junto a esta forma tan conveniente de desestructurar un array, ES6 nos regala dos operadores, que voy a llamar "esparcir" y "recolectar" (*). Aquí tienes un adelanto, porque voy a dedicar un artículo específicamente a ellos. Supón que quieres desestructurar sólo parte del array y usar el resto como array. Podemos usar el operador "recolectar":
function uglyAPI() { return [1, 2, 3, 4, 5, 6, 7, 8]; }
var [ a, b, c, ...resto ] = uglyAPI();
console.log(a, b, c, resto); // 1 2 3 [4, 5, 6, 7, 8]
¿Y si quiero convertir el array a un objeto?
function uglyAPI() { return [1, 2, 3, 4, 5, 6, 7, 8]; }
var obj = {};
[
obj.a,
obj.b,
obj.c,
...obj.resto ] = uglyAPI();
console.log( obj ); // {a:1, b:2, c:3, resto:[4, 5, 6] }
Una vez que te familiarizas con esta sintaxis, te enganchas y empiezas a verle todo tipo de aplicaciones.
Por ejemplo, para intercambiar valores de dos variables antes tenías que crear una variable temporal y hacer esta poco elegante secuencia de operaciones:
var x = 10;
var y = 20;
//...
var tmp = y;
x = a;
y = tmp;
Ahora con una sola línea basta y hasta es fácil que alguien no familiarizado con esta forma de hacer las cosas adivine qué estás haciendo:
[x, y] = [y, x];
Si has llegado hasta aquí, espero no haberte perdido por el camino y que te hayas quedado con hambre de más. Si es así nos vemos en la parte II.
(*): Esta terminología la tomo prestada de las enseñanzas de Kyle Simpson. Él los llama spread and gather operators en su libro You don’t know JS y yo me he tomado la libertad de traducir los términos.