Herramientas de usuario

Herramientas del sitio


informatica:programacion:cursos:programacion_avanzada_javascript:desestructuracion

Diferencias

Muestra las diferencias entre dos versiones de la página.

Enlace a la vista de comparación

Ambos lados, revisión anteriorRevisión previa
Próxima revisión
Revisión previa
informatica:programacion:cursos:programacion_avanzada_javascript:desestructuracion [2024/10/17 10:56] – [DEMO: Desestructuración en arrays] tempwininformatica:programacion:cursos:programacion_avanzada_javascript:desestructuracion [2024/10/17 12:42] (actual) – [DEMO: Parámetros rest] tempwin
Línea 170: Línea 170:
 arr = [10, 20, 30, 40]; arr = [10, 20, 30, 40];
  
-[i,,,f] = arr;+var [i,,,f] = arr;
  
 i; // -> 10 i; // -> 10
 f; // -> 40 f; // -> 40
 +</code>
 +
 +Incluso podemos hacerlo con arrays más pequeños de lo esperado y no nos dará error:
 +
 +<code javascript>
 +var [e,,,f] = [10];
 +
 +e; // -> 10
 +f; // -> 'undefined'
 </code> </code>
 ===== Desestructuración en objetos ===== ===== Desestructuración en objetos =====
 +
 +La desestructuración también funciona en objetos. Es decir, se puede desestructurar un objeto y asignar todas o algunas de sus propiedades a variables simples:
 +
 +<code javascript>
 +var obj = {a: 10, b: 42};
 +// Sin desestructuración
 +var x = obj.a;
 +var y = obj.b;
 +// Usando desestructuración
 +var {a: x, b: y}  = obj;
 +</code>
 +
 +Al finalizar el código el valor de ''x'' es ''10'' (el valor de la propiedad ''a'' del objeto ''obj''). Y el valor de ''y'' es ''42''.
 +
 +Podemos desestructurar parcialmente un objeto, no necesitamos desestructurar todas sus propiedades:
 +
 +<code javascript>
 +var {b: x} = {a: 10, b: 42}
 +</code>
 +
 +Al finalizar el código la variable ''x'' vale ''42''.
 +
 +Por supuesto, puede combinarse la desestructuración de arrays y objetos:
 +
 +<code javascript>
 +var data = {a:10, b:[1,2,3, {c: 40, d: 50}]};
 +var  {b: [,x]} = data;
 +</code>
 +
 +Al finalizar este código el valor de ''x'' es ''2'', que es el segundo elemento del array ''data.b''. Como puedes ver el poder de la desestructuración es enorme.
 +
 +==== Desestructuración en parámetros ====
 +
 +La gestión de parámetros opcionales en las funciones en JavaScript siempre ha sido problemática. Cierto es que usando ''typeof'' y el operador ''||'' se puede conseguir mucha flexibilidad, pero el principal problema sigue siendo que viendo la firma de la función uno no sabe qué parámetros pasarle. Mejor veámoslo con un ejemplo:
 +
 +<code javascript>
 +var foo = function(params) {
 +    var uri = params.uri;
 +    var method = params.method || 'GET';
 +    var contentType = params.contentType || 'application/json';
 +    // Hacer la petición a la uri indicada con el método y content-type indicados
 +}
 +// Uso de la función:
 +foo({uri: 'http://campusmvp.es'});  // method es GET y contentType es 'application/json'
 +foo({uri: 'http://campusmpv.es', contentType: 'text/html', method: 'GET'});
 +</code>
 +
 +El principal problema para alguien que quiera llamar a ''foo'' es ¿cómo sabe cuáles son las propiedades del objeto que se le debe pasar como parámetro?
 +
 +No hay más solución que leerse todo el código fuente de la función. Solo así podemos ver que la función ''foo'' espera las propiedades ''uri'', ''method'' y ''contentType'' dentro del objeto. Usar la desestructuración ayuda a explicitar este hecho:
 +
 +<code javascript>
 +var foo = function({uri: uri, method: method, contentType: contentType}) {
 +    // En este punto las variables uri, method y contentType ya existen gracias a la desestructuración
 +}
 +</code>
 +
 +Para quien llame a ''foo'' no hay diferencia entre ambas versiones, pero la segunda deja mucho más claras las propiedades que se esperan en el objeto que se recibe como parámetro. En este ejemplo el nombre de la propiedad (a la izquierda de los dos puntos) y el de la variable local generada por la desestructuración (a la derecha de los dos puntos) son iguales, aunque no tiene por qué. Pero si este es el caso todavía podemos simplificar más el código:
 +
 +<code javascript>
 +var foo = function({uri, method, contentType}) {
 +    // En este punto las variables uri, method y contentType ya existen gracias a la desestructuración
 +}
 +</code>
 +
 +<WRAP center round info 60%>
 +Recuerda que en ECMAScript 2015 si usamos notación de objeto y una propiedad "''x''" se inicializa a partir de una variable llamada "''x''" no tenemos por qué poner ''{x:x}'', sino que podemos poner simplemente ''{x}''.
 +</WRAP>
 +
 +Incluso podemos ir un paso más allá y **dar valores por defecto a las propiedades no pasadas**:
 +
 +<code javascript>
 +var foo = function({uri, method: method='GET', contentType: ctype='application/json'}) {
 +    // En este punto las variables uri, method y ctype ya existen gracias a la desestructuración
 +}
 +</code>
 +
 +En este caso si el llamante no especifica el valor de las propiedades ''method'' y ''contentType'' éstas toman los valores por defecto.
 +
 +<WRAP center round info 60%>
 +Observa que cuando usamos los valores por defecto, aunque la variable resultado de la desestructuración se llame igual que la propiedad del objeto, debemos especificar ambos (caso de ''method'' en el ejemplo anterior).
 +</WRAP>
 +
  
 ===== DEMO: Desestructuración en objetos ===== ===== DEMO: Desestructuración en objetos =====
  
 +<code javascript>
 +var obj = {
 +  a: 10,
 +  b: 42
 +};
 +</code>
 +
 +Sin desestructuración:
 +
 +<code javascript>
 +var x = obj.a;
 +var y = obj.b;
 +</code>
 +
 +Con la desestructuración:
 +
 +<code javascript>
 +var {a: x, b: y} = obj;
 +</code>
 +
 +Como vemos, ponemos primero el nombre de la propiedad que queremos desestructurar y luego la variable que recibirá el valor de la desestructuración.
 +
 +<code javascript>
 +console.log(x, y); // -> 10 42
 +</code>
 +
 +Podemos desestructurar parte del objeto:
 +
 +<code javascript>
 +var { b: z } = obj;
 +
 +console.log(z); // -> 42
 +</code>
 +
 +Desestructurando propiedades que no existen:
 +
 +<code javascript>
 +var {a: x, _b: y} = obj;
 +
 +console.log(x, y); // 10 'undefined'
 +</code>
 +
 +En resumen, la desestructuración nos permite extraer elementos de un array o valores de propiedades de un objeto a variables simples. Y extraer todos y algunos elementos. Si no existen las variables a desestructurar, se asignará ''undefined''.
 ===== DEMO: Desestructuración en parámetros ===== ===== DEMO: Desestructuración en parámetros =====
  
 +Es muy habitual en JavaScript hacer funciones que acepten un objeto como parámetro. En la firma de la función no sabemos qué propiedades tendrá ese objeto:
 + 
 +<code javascript>
 +var f = function(params) {
 +    console.log(params.url);
 +}
 +
 +f({url: "campusmvp.es"});
 +</code>
 +
 +Con la desestructuración:
 +
 +<code javascript>
 +var f = function({url: x}) {
 +    console.log(x);
 +}
 +
 +f({url: "campusmvp.es"});
 +</code>
 +
 +Esto permite tener parámetros nombrados dentro de un objeto y ayudar a la legibilidad del código.
 ===== Operador spread ===== ===== Operador spread =====
 +
 +El operador **spread** permite que en situaciones en las que se espera un valor, aparezcan varios valores. Es un operador muy potente, y la mejor manera de entenderlo es verlo en acción.
 +
 +Empecemos viéndolo en combinación con la desestructuración:
 +
 +<code javascript>
 +var [a,b,...c] = [10, 20, 30, 40, 50];
 +</code>
 +
 +El operador **spread** son los tres puntos (''...''). En este caso estamos aplicando el operador a la variable ''c''. Por la desestructuración la variable ''c'' tomaría el tercer valor del array, pero gracias al operador **spread** puede tomar más de uno. El resultado es que la variable ''c'' termina siendo un array con el resto de valores del array desestructurado. Es decir, la variable ''c'' pasa a ser un array con los valores ''30'', ''40'' y ''50''.
 +
 +<WRAP center round info 60%>
 +Cuando el operador **spread** se usa de ese modo, tan solo puede aparecer una vez y en el último lugar.
 +</WRAP>
 +
 +Otro uso interesante del operador es llamar a funciones con N parámetros a partir de un array con N valores:
 +
 +<code javascript>
 +var foo = function(a,b) {
 +  console.log(a,b);
 +}
 +foo(...[10,20]);
 +</code>
 +
 +Observa cómo llamamos a la función ''foo'' y le pasamos como parámetro el operador //spread// aplicado al array ''[10, 20]''. Al aplicar el operador //spread// de esa forma el primer valor del array pasa al primer parámetro de la función, el segundo valor del array al segundo parámetro y así sucesivamente. Eso nos permite invocar a funciones con varios parámetros, cuando tenemos esos parámetros en un array sin necesidad de usar ''apply''.
 +
 +Se pueden combinar varios operadores spread llamando a una función, y eso se puede combinar con parámetros normales. La flexibilidad es total:
 +
 +<code javascript>
 +var foo = function(a,b,c,d,e) {
 +}
 +foo(10, ...[20, 30], 40, ...[50]);
 +</code>
 +
 +En este código...
 +
 +  * El valor del parámetro ''a'' se toma de la constante ''10''
 +  * El valor del parámetro ''b'' se toma del primer valor del array ''[20, 30]'' gracias al operador spread
 +  * El valor del parámetro ''c'' se toma del segundo valor del array ''[20, 30]'' gracias al operador spread
 +  * El valor del parámetro ''d'' se toma de la constante ''40''
 +  * El valor del parámetro ''e'' se toma del primer (y único) valor del array ''[50]'' gracias al operador spread
 +
 +==== Parámetros rest ====
 +
 +El operador //spread// se puede aplicar al último parámetro de una función. Cuando hacemos esto decimos que este parámetro es un "parámetro rest". El valor de un parámetro rest es un array con todos los valores que se hayan pasado a la función y que no estén en ningún parámetro nombrado (convencional). Solo puede haber un parámetro rest en una función y debe ser el último:
 +
 +<code javascript>
 +var foo = function(a,b, ...c) {}
 +foo(10, 20, 30);        // c vale [30]
 +foo(10, 20, 30, 40);    // c vale [30, 40]
 +foo(10,20);             // c vale [] (es decir, un array vacío, no undefined)
 +</code>
 +
 +Quizá te preguntes qué aportan los parámetros //rest//, existiendo ''arguments''. Pues dos cosas importantes. La primera es que un parámetro //rest// solo tiene los valores que no están en ningún parámetro nombrado (''c'' solo contiene los valores adicionales que no están en ''a'' ni en ''b''), mientras que ''arguments'' contiene siempre todos los parámetros pasados. Pero la diferencia más importante es que **''arguments'' no es un array**. Se le parece (es lo que llamamos un //array-like object//) pero no lo es. Y eso implica que no podemos usar todas las funciones de ''Array.prototype'' en ''arguments''. Mientras que un parámetro //rest// sí que es un array de verdad.
  
 ===== DEMO: Operador spread ===== ===== DEMO: Operador spread =====
 +
 +Desestructuración normal:
 +
 +<code javascript>
 +var arr = [1,2,3,4,5,6,7];
 +
 +var [x,,,y] = arr;
 +
 +console.log(x,y); // -> 1 4
 +</code>
 +
 +Aplicando el operador //spread// (''...''):
 +
 +<code javascript>
 +var arr = [1,2,3,4,5,6,7];
 +
 +var [x,,,y,...z] = arr;
 +
 +console.log(x,y); // -> 1 4 Array [ 5, 6, 7 ]
 +</code>
 +
 +El operador //spread// permite que varios valores se obtengan en un nuevo array.
 +
 +Este operador también nos permite combinar fácilmente arrays:
 +
 +<code javascript>
 +var uno = [1, 2, 5, 6];
 +
 +// Queremos que el segundo array tenga unos elementos y el anterior array:
 +var dos = [100, 200, ...uno, 300];
 +
 +dos;// Array [ 100, 200, 1, 2, 5, 6, 300 ]
 +</code>
 +
 +Otro de los usos de este operador es para las funciones sin necesidad de usar ''apply'':
 +
 +<code javascript>
 +var foo = function(a, b, c, d, e) {
 +    console.log(a, b, c, d, e);
 +}
 +</code>
 +
 +Uso:
 +<code javascript>
 +var arr = [1,2,3,4,5];
 +
 +// Imaginemos que queremos asociar cada uno de esos valores del array
 +// a los distintos argumentos de la función 'foo'. Con spread es así de fácil:
 +foo(...arr);
 +</code>
 +
 +Si tuviéramos menos elementos:
 +
 +<code javascript>
 +var arr = [1,2,3,4,5];
 +
 +// El resto de parámetros de la función se los podríamos
 +// pasar así:
 +foo(...arr, 100, 200);
 +</code>
 +
 +También es posible hacer esto:
 +
 +<code javascript>
 +var arr = [1,2,3,4,5];
 +var arr2 = [200, 300];
 +
 +
 +foo(...arr, ...arr2);
 +
 +También podemos hacer:
 +
 +foo(...arr, ...[10], ...[30]);
 +</code>
 +
  
 ===== DEMO: Parámetros rest ===== ===== DEMO: Parámetros rest =====
 +
 +Llamamos parámetros //rest// a que podemos aplicar el operador //spread// como último parámetro de una función y este último parámetro será un array que contendrá todos los parámetros no nombrados de la función.
 +
 +<code javascript>
 +var foo = function(a, b, ...c) {
 +    console.log(a);
 +    console.log(b);    
 +    console.log(c);   
 +}
 +
 +foo(10, 20, 30); 
 +// 10
 +// 20
 +// Array [ 30 ]
 +
 +foo(10, 20, 30, 40, 50, 60);
 +// 10
 +// 20
 +// Array [ 30, 40, 50, 60 ]
 +</code>
 +
 +Los parámetros //rest// no fallan, por ejemplo, veamos qué pasa si le pasamos a la función todos los argumentos menos los //rest//:
 +
 +<code javascript>
 +foo(10, 20);
 +
 +// 10
 +// 20
 +// Array [ ]
 +</code>
 +
 +Vamos a ver diferencias con ''arguments'':
 +
 +<code javascript>
 +var foo = function(a, b, ...c) {
 +    console.log(a);
 +    console.log(b);    
 +    console.log(c);   
 +    console.log(arguments);
 +}
 +</code>
 +
 +Usamos:
 +
 +<code javascript>
 +foo(10, 20, 30, 40); 
 +// 10
 +// 20
 +// Array [ 30, 40 ]
 +// Arguments { , 7 more... }
 +</code>
 +
 +''arguments'' contiene todos los parámetros, ya sean nombrados o no. rest solo contiene los nombrados. El parámetro //rest// es un array, ''arguments'' no es un array, así que no podemos usar operaciones típicas de arrays (''map'', ''filter'').
informatica/programacion/cursos/programacion_avanzada_javascript/desestructuracion.1729155362.txt.gz · Última modificación: por tempwin