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:07] – [Inclusión de elementos en una matriz] tempwin | informatica:programacion:cursos:programacion_avanzada_javascript:otras_caracteristicas_ecmascript [2024/10/30 13:13] (actual) – [Paréntesis obligatorios] tempwin | ||
|---|---|---|---|
| Línea 100: | Línea 100: | ||
| 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 '' | 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 " | + | ==== Simulando valores por defecto para parámetros opcionales en JavaScript " |
| - | En JavaScript (ECMAScript 5) podemos sacar partido de los valores " | + | En JavaScript (ECMAScript 5) podemos sacar partido de los valores " |
| - | Como sabes, el operador lógico OR (||) se evalúa con cortocircuito de expresiones lógicas de la siguiente manera: | + | Como sabes, el operador lógico OR ('' |
| - | | + | * Si el primer operando de la comparación es '' |
| - | Si el primer operando es false, entonces se devuelve automáticamente el segundo operando. | + | |
| 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 " | 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 sumar que toma dos parámetros, | + | Por ejemplo, si tenemos una función |
| + | <code javascript> | ||
| function sumar(a, b) { | function sumar(a, b) { | ||
| a = a || 0; | a = a || 0; | ||
| Línea 118: | Línea 119: | ||
| return a+b; | 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 a (es decir, se recibe un undefined) se le asignará automáticamente un 0 como valor por defecto. Y lo mismo con b. Al evaluarse el operador OR (||) el primer parámetro se convierte en un booleano. Si no está definido esto es equivalente a un " | + | 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 true y por lo tanto se devolverá el propio objeto (se reasignará a sí mismo). | + | 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 true, si usamos esta técnica, cuando se le pasase un false como valor para el parámetro, el efecto que obtendríamos es que se cambiaría su valor a true y, en la práctica, no lograríamos nunca pasarle un false como valor efectivo. Y si esperásemos una cadena de texto y nos valiesen también cadenas de texto vacías, al hacer algo como esto: | + | **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) { | function test(p) { | ||
| p = p || ' | p = p || ' | ||
| Línea 130: | Línea 133: | ||
| } | } | ||
| console.log(test('' | console.log(test('' | ||
| + | </ | ||
| - | veríamos por la consola la cadena ' | + | veríamos por la consola la cadena |
| Existen, por supuesto, formas de lograr lo mismo en estas situaciones, | 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 | + | ==== 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. | + | 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 |
| - | Este operador se representa por una doble interrogación ?? y sirve precisamente para lograr de manera sencilla y directa lo que acabamos de describir: ofrecer un valor por defecto cuando un elemento al que necesitamos acceder no existe, es nulo o está sin definir (undefined). | + | Este operador se representa por una **doble interrogación** '' |
| - | Este operador lleva existiendo en otros lenguajes desde hace mucho tiempo (en C#, por ejemplo, desde hace 15 años al menos), pero en JavaScript/ | + | 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: var resultado = valor ?? valorXDefecto. | + | 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í: | Con él, nuestra función de suma con parámetros opcionales quedaría así: | ||
| + | <code javascript> | ||
| function sumar(a, b) { | function sumar(a, b) { | ||
| a = a ?? 0; | a = a ?? 0; | ||
| Línea 154: | Línea 159: | ||
| return a+b; | return a+b; | ||
| } | } | ||
| + | </ | ||
| En este caso siempre va a funcionar bien, no como ocurría con la técnica convencional, | 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 ?? se comprueba para ver si es null o undefined, o lo que es lo mismo: " | + | Lo importante a considerar aquí es que el valor a la izquierda del operador |
| + | <code javascript> | ||
| var res = false ?? true; // --> false | var res = false ?? true; // --> false | ||
| res = '' | res = '' | ||
| res = 0 ?? 1; // --> 0 | res = 0 ?? 1; // --> 0 | ||
| + | </ | ||
| - | no lo son para el operador de nullish coalescing. | + | no lo son para el operador de //nullish coalescing//. |
| - | Paréntesis obligatorios | + | |
| - | ¿Qué ocurre si combinas este operador ?? con otros operadores de tipo lógico? Por ejemplo, ¿cuál sería el resultado de esto?: | + | ==== Paréntesis obligatorios ==== |
| + | ¿Qué ocurre si combinas este operador ''??'' | ||
| + | |||
| + | <code javascript> | ||
| var a = 0; | var a = 0; | ||
| var b = false; | var b = false; | ||
| var res = a || b ?? true; | var res = a || b ?? true; | ||
| + | </ | ||
| - | El resultado es que se produce un error: Unexpected token ??: | + | El resultado es que **se produce un error**: '' |
| - | El error que se produce | + | {{ : |
| 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: | 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: | ||
| - | | + | * '' |
| - | a || (b ?? true) | + | * '' |
| y en ambos casos tiene sentido. | y en ambos casos tiene sentido. | ||
| - | Así que los diseñadores de esta característica decidieron que no puede utilizarse con || o && salvo que especifiquemos claramente la precedencia mediante paréntesis. De este modo se fuerza a que el programa tome la decisión sobre cómo interpretarlo y además facilita su lectura inequívoca por parte de cualquiera. | + | 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 " | + | ==== Cortocircuito |
| + | Un último detalle sobre el operador: al igual que sus " | ||
| + | |||
| + | <code javascript> | ||
| var res = " | 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 ''? | ||
| - | En este ejemplo, como el operando de la izquierda no es null ni undefined | + | El soporte de este operador es total en los navegadores // |
informatica/programacion/cursos/programacion_avanzada_javascript/otras_caracteristicas_ecmascript.1730214436.txt.gz · Última modificación: por tempwin
