informatica:programacion:cursos:programacion_avanzada_javascript:otras_caracteristicas_ecmascript
Diferencias
Muestra las diferencias entre dos versiones de la página.
| Ambos lados, revisión anteriorRevisión previaPróxima revisión | Revisión previa | ||
| informatica:programacion:cursos:programacion_avanzada_javascript:otras_caracteristicas_ecmascript [2024/10/29 16:02] – tempwin | informatica:programacion:cursos:programacion_avanzada_javascript:otras_caracteristicas_ecmascript [2024/10/30 13:13] (actual) – [Paréntesis obligatorios] tempwin | ||
|---|---|---|---|
| Línea 19: | Línea 19: | ||
| Existe una excepción a esta norma y tiene que ver con '' | Existe una excepción a esta norma y tiene que ver con '' | ||
| + | |||
| + | ===== Valores por defecto para parámetros opcionales ===== | ||
| + | |||
| + | Una necesidad muy habitual a la hora de programar es la de obtener **valores por defecto para los parámetros de las funciones**. | ||
| + | |||
| + | Al contrario que en otros lenguajes como C# o Java, en JavaScript no hay manera de forzar la definición de una función y sus parámetros. Podemos definir una función con tantos parámetros como deseemos, pero eso no significa que luego otros programadores nos los vayan a pasar siempre. | ||
| + | |||
| + | Por ejemplo, en C# defines una función tan simple como esta: | ||
| + | |||
| + | <code c> | ||
| + | int Sumar(int a, int b) | ||
| + | { | ||
| + | return a+b; | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | Que suma dos enteros y siempre tienes que pasarle dos enteros para que funcione. Es decir, intentar una llamada a '' | ||
| + | |||
| + | Esto parece una obviedad, pero en JavaScript eso no es así en absoluto. Si defino la misma función en este lenguaje: | ||
| + | |||
| + | <code javascript> | ||
| + | function sumar(a, b) { | ||
| + | return a+b; | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | Podría llamarla de la manera obvia: '' | ||
| + | |||
| + | Y es que **en JavaScript todos los parámetros de una función son opcionales**. | ||
| + | |||
| + | En ECMASCript 2015 se añadió la posibilidad de prever esta posibilidad especificando el valor que queremos otorgarle a un parámetro opcional cuando no se pasa. Por ejemplo, la función anterior podríamos definirla así: | ||
| + | |||
| + | <code javascript> | ||
| + | function Sumar(a = 0, b = 0) | ||
| + | { | ||
| + | return a+b; | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | Y ahora sí, podría llamarla como quisiera: pasándole dos, uno o ningún parámetro. En caso de que falte alguno, su valor sería el especificado por defecto, en este caso un 0. También podrían pasarnos más de 2 parámetros, | ||
| + | |||
| + | De hecho, esta funcionalidad de parámetros por defecto es mas flexible en ECMAScript que en otros lenguajes, como C#, ya que nos permite usar valores de parámetros anteriores para los parámetros opcionales: | ||
| + | |||
| + | <code javascript> | ||
| + | function Sumar(a = 0, b = a) { | ||
| + | return a+b; | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | En este caso, por ejemplo, si no nos pasan el primer argumento le ponemos un 0, pero si no nos pasa en el segundo, le ponemos como valor por defecto ¡lo que valga el primer parámetro!. Incluso podríamos hacer operaciones con ellos o aplicarles funciones, lo que está muy bien. | ||
| + | |||
| + | El problema de estos parámetros opcionales es que **sólo actúan si no se le pasa nada**, es decir, que si le pasamos algo que no sea un '' | ||
| + | |||
| + | <code javascript> | ||
| + | function Sumar(a = 1, b = 1) { | ||
| + | return a+b; | ||
| + | } | ||
| + | |||
| + | console.log(Sumar(null, | ||
| + | </ | ||
| + | |||
| + | En este caso llamamos a la función pasándole dos nulos, y en vez de recibir un '' | ||
| + | |||
| + | La única excepción a esto es que le pasemos un valor '' | ||
| + | |||
| + | <code javascript> | ||
| + | var v1, v2; | ||
| + | |||
| + | function Sumar(a = 1, b = 1) { | ||
| + | return a+b; | ||
| + | } | ||
| + | |||
| + | console.log(Sumar(v1, | ||
| + | </ | ||
| + | |||
| + | En este caso las variables que pasamos a la función están declaradas pero no definidas por lo que, aunque se las pasemos al a función, es como si no le hubiésemos pasado nada. | ||
| + | |||
| + | La funcionalidad, | ||
| + | |||
| + | Por ello, aunque muy útil, no siempre nos va a servir. Muchas veces lo que necesitamos es ofrecer un valor por defecto si el parámetro no está (o sea, es '' | ||
| + | |||
| + | ==== Simulando valores por defecto para parámetros opcionales en JavaScript " | ||
| + | |||
| + | En JavaScript (ECMAScript 5) podemos sacar partido de los valores " | ||
| + | |||
| + | Como sabes, el operador lógico OR ('' | ||
| + | |||
| + | * Si el primer operando de la comparación es '' | ||
| + | * Si el primer operando es '' | ||
| + | |||
| + | Sacando partido a esto es muy fácil definir valores por defecto para los parámetros sin tener que escribir condicionales ni código largo que " | ||
| + | |||
| + | Por ejemplo, si tenemos una función '' | ||
| + | |||
| + | <code javascript> | ||
| + | function sumar(a, b) { | ||
| + | a = a || 0; | ||
| + | b = b || 0; | ||
| + | return a+b; | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | Por el efecto que acabo de explicar, lo que se consigue con la primera línea del cuerpo de la función, es que si no se le pasa a la misma el parámetro '' | ||
| + | |||
| + | Si se le pasa una cadena o un objeto de cualquier tipo se evaluará como '' | ||
| + | |||
| + | **Pero esto tiene algunos fallos**. Por ejemplo, si el parámetro que esperábamos es un **booleano** y queremos que el valor por defecto sea '' | ||
| + | |||
| + | <code javascript> | ||
| + | function test(p) { | ||
| + | p = p || ' | ||
| + | return p; | ||
| + | } | ||
| + | console.log(test('' | ||
| + | </ | ||
| + | |||
| + | veríamos por la consola la cadena ''' | ||
| + | |||
| + | Existen, por supuesto, formas de lograr lo mismo en estas situaciones, | ||
| + | |||
| + | El resumen de lo anterior es que, con JavaScript " | ||
| + | |||
| + | ==== Cómo hacerlo bien con ECMAScript ==== | ||
| + | |||
| + | Por suerte, desde ECMAScript 2020 existe una manera mucho mejor de lograrlo: el **operador de unión nulosa**, más conocido por su extraño nombre en inglés operador //nullish coalescing// | ||
| + | |||
| + | Este operador se representa por una **doble interrogación** ''??'' | ||
| + | |||
| + | Este operador lleva existiendo en otros lenguajes desde hace mucho tiempo ([[https:// | ||
| + | |||
| + | Su uso es muy sencillo: se pone a continuación de un valor que creamos que puede ser nulo o no definido y, en caso de que lo sea, devolverá lo que pongamos a su derecha, es decir, esto: '' | ||
| + | |||
| + | Con él, nuestra función de suma con parámetros opcionales quedaría así: | ||
| + | |||
| + | <code javascript> | ||
| + | function sumar(a, b) { | ||
| + | a = a ?? 0; | ||
| + | b = b ?? 0; | ||
| + | return a+b; | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | En este caso siempre va a funcionar bien, no como ocurría con la técnica convencional, | ||
| + | |||
| + | Lo importante a considerar aquí es que el valor a la izquierda del operador ''??'' | ||
| + | |||
| + | <code javascript> | ||
| + | var res = false ?? true; // --> false | ||
| + | res = '' | ||
| + | res = 0 ?? 1; // --> 0 | ||
| + | </ | ||
| + | |||
| + | no lo son para el operador de //nullish coalescing// | ||
| + | |||
| + | ==== Paréntesis obligatorios ==== | ||
| + | |||
| + | ¿Qué ocurre si combinas este operador ''??'' | ||
| + | |||
| + | <code javascript> | ||
| + | var a = 0; | ||
| + | var b = false; | ||
| + | var res = a || b ?? true; | ||
| + | </ | ||
| + | |||
| + | El resultado es que **se produce un error**: '' | ||
| + | |||
| + | {{ : | ||
| + | |||
| + | El motivo es que, al combinar este tipo de operadores, hagas lo que hagas con la precedencia no puedes evitar que la interpretación que hace el programador de lo que está escribiendo entre en conflicto con lo que el diseñador del lenguaje haya decidido. Por ejemplo, en el fragmento anterior, eso se puede interpretar como: | ||
| + | |||
| + | * '' | ||
| + | * '' | ||
| + | |||
| + | y en ambos casos tiene sentido. | ||
| + | |||
| + | Así que los diseñadores de esta característica decidieron que **no puede utilizarse con '' | ||
| + | |||
| + | ==== Cortocircuito de expresiones ==== | ||
| + | |||
| + | Un último detalle sobre el operador: al igual que sus " | ||
| + | |||
| + | <code javascript> | ||
| + | var res = " | ||
| + | </ | ||
| + | |||
| + | En este ejemplo, como el operando de la izquierda no es '' | ||
| + | |||
| + | ===== El operador de encadenamiento opcional: evitando errores por nulos ===== | ||
| + | |||
| + | El operador de encadenamiento opcional, ''? | ||
| + | |||
| + | Un caso habitual es el siguiente: estamos accediendo a un servicio que nos devuelve información de objetos que necesitamos para nuestra aplicación. Estos objetos pueden tener a su vez varios subobjetos a los que necesitamos acceder para hacer cosas, por ejemplo: | ||
| + | |||
| + | <code javascript> | ||
| + | if (usuario.direccion.planta.length > 0) { | ||
| + | //lo que sea... | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | El problema de lo anterior es que es posible que el usuario no tenga dirección, y si la tiene quizá no tiene el campo de la planta en la que vive (porque es una casa unifamiliar, | ||
| + | |||
| + | <code javascript> | ||
| + | if (usuario && usuario.direccion && usuario.direccion.planta) { | ||
| + | if (usuario.direccion.planta.length > 0) { | ||
| + | //lo que sea... | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | Es decir, antes de poder utilizar nuestra expresión original debemos comprobar que todos los elementos de la cadena de propiedades existen (no son nulos), para asegurarnos de que no se produce un error. | ||
| + | |||
| + | <WRAP center round tip 60%> | ||
| + | Obviamente sólo es necesario comprobar aquellos que puedan estar nulos. Por ejemplo, su el usuario siempre va a existir como resultado de la llamada al servicio (o sea, el servicio no nos va a devolver nunca un nulo), la primera comprobación ('' | ||
| + | </ | ||
| + | |||
| + | Lo anterior funciona porque el operador AND (''&&'' | ||
| + | |||
| + | Este tipo de expresiones es muy habitual verlas por ahí y funcionan bien, pero **son tediosas de escribir, largas y no contribuyen precisamente a la claridad del código**. | ||
| + | |||
| + | Por suerte, ECMAScript nos proporciona un elemento específico para facilitarnos la vida: el operador de encadenamiento opcional: ?.. Gracias a él podemos escribir esto: | ||
| + | |||
| + | <code javascript> | ||
| + | if (usuario? | ||
| + | //lo que sea... | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | Es decir, al ponerlo delante de una propiedad, ésta **sólo se evalúa si el objeto precedente no es nulo ni '' | ||
| + | |||
| + | Lo que se obtiene en caso de que algún punto de la cadena sea nulo o no definido es **un valor no definido**, o sea '' | ||
| + | |||
| + | Esto es equivalente a usar todos aquellos ''&&'' | ||
| + | |||
| + | <WRAP center round important 60%> | ||
| + | MUY IMPORTANTE: el primer objeto de la cadena debe existir y estar definido, ya que el operador necesita al menos un objeto " | ||
| + | </ | ||
| + | |||
| + | ==== Llamadas a funciones ==== | ||
| + | |||
| + | Pero este operador sirve para más cosas que simplemente encadenar propiedades de objetos. También es posible utilizarlo para hacer **llamadas a funciones, sólo si la función está definida**. Por ejemplo: | ||
| + | |||
| + | <code javascript> | ||
| + | var res = usuario? | ||
| + | </ | ||
| + | |||
| + | Esta sintaxis tan rara, ''? | ||
| + | |||
| + | Es importante señalar que si el supuesto método existe pero no es un método, se producirá un error de tipos. Es decir, lo anterior funciona si el miembro que queremos llamar no existe. Pero, en nuestro ejemplo, si '' | ||
| + | |||
| + | ==== Cortocircuito de expresiones ==== | ||
| + | |||
| + | Este operador también incluye cortocircuito de expresiones. Es decir, que en cuanto se encuentra un eslabón de la cadena que es nulo o no definido, no sigue evaluando los demás. Así, por ejemplo: | ||
| + | |||
| + | <code javascript> | ||
| + | var n = 0; | ||
| + | var res = usuario? | ||
| + | </ | ||
| + | |||
| + | ...si el usuario o si la función '' | ||
| + | |||
| + | ==== Acceso a arrays ==== | ||
| + | |||
| + | En JavaScript una alternativa a la sintaxis '' | ||
| + | |||
| + | <code javascript> | ||
| + | var color = usuario.ajustes[' | ||
| + | </ | ||
| + | |||
| + | que es equivalente a: | ||
| + | |||
| + | <code javascript> | ||
| + | var color = usuario.ajustes.color; | ||
| + | </ | ||
| + | |||
| + | La ventaja de la primera sintaxis es que nos permite decidir el nombre de la propiedad dinámicamente, | ||
| + | |||
| + | <code javascript> | ||
| + | var nomAjuste = obtenerNombreAjusteColor(); | ||
| + | var color = usuario.ajustes.[nomAjuste]; | ||
| + | </ | ||
| + | |||
| + | cosa que no podríamos hacer con la sintaxis habitual del punto. | ||
| + | |||
| + | En este caso, si la propiedad es nula o no está definida JavaScript devuelve un error. O sea, en este ejemplo si el servicio nos devuelve un '' | ||
| + | |||
| + | Para facilitar este caso, una tercera sintaxis de este operador nos permite **acceder al contenido de arrays o colecciones aunque sean nulas o no estén definidas**: | ||
| + | |||
| + | <code javascript> | ||
| + | var color = usuario? | ||
| + | </ | ||
| + | |||
| + | En este caso está intentando acceder a las propiedades del objeto '' | ||
| + | |||
| + | Fíjate además que, por el cortocircuito de expresiones, | ||
| + | |||
| + | Nos vale también para arrays normales y corrientes accedidas mediante índice: | ||
| + | |||
| + | <code javascript> | ||
| + | var color = usuario? | ||
| + | </ | ||
| + | |||
| + | De este modo si '' | ||
| + | |||
| + | ==== Devolver algo diferente a no definido ==== | ||
| + | |||
| + | Finalmente, podemos combinar ese nuevo operador con el operador de unión " | ||
| + | |||
| + | <code javascript> | ||
| + | var color = usuario? | ||
| + | </ | ||
| + | |||
| + | que en caso de no estar definido devolvería un color por defecto (el color blanco). | ||
| + | |||
| + | ==== En resumen ==== | ||
| + | |||
| + | El operador ''? | ||
| + | |||
| + | El soporte de este operador es total en los navegadores // | ||
informatica/programacion/cursos/programacion_avanzada_javascript/otras_caracteristicas_ecmascript.1730214178.txt.gz · Última modificación: por tempwin
