Menú de navegaciónMenú
Categorías

La mejor forma de Aprender Programación online y en español www.campusmvp.es

?id=f2850390-4a5c-41cc-8ede-5eafa53d8c17

El operador de encadenamiento opcional en ECMAScript/JavaScript: evitando errores por nulos

Fotografía ornamental, un signo de interrogación y un punto formado por islas, en Jablines (Francia), por Jules Bss, CC0 en Unsplash

Hace unas semanas hablaba aquí del operador de "unión nulosa" de ECMAScript 2020 utilizado sobre todo para obtener valores por defecto en expresiones, es decir, para asignar fácilmente y de manera legible valores alternativos a elementos nulos necesarios para que trabaje una función. Puede sonar a "cosa rara", pero lo cierto es que es de lo más útil y una vez que lo aprendes lo usarás todo el rato.

Hoy me voy a enfocar en un primo hermano del anterior: el operador de encadenamiento opcional que nos permite simplificar enormemente las expresiones con propiedades o arrays que podrían tener valores nulos.

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:

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, por ejemplo). Por lo que la expresión anterior no se puede utilizar ya que cualquier punto de la cadena de propiedades puede ser nulo y fallar. Por ello, en estos casos se suele escribir algo como esto:

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.

Obviamente sólo es necesario comprobar aquellos que puedan estar nulos. Por ejemplo, si 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 (if (usuario)) no es necesaria.

Lo anterior funciona porque el operador AND (&&) tiene cortocircuito de expresiones, es decir, dado que para ser cierto ambas partes de la comparación deben ser ciertas, en cuanto la primera no lo es ya no se comprueba la segunda, por lo que en cuanto cualquier parte de la cadena de propiedades se encuentra un nulo, no se evalúan las demás, y no se produce nunca un error por nulos.

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 2020 ha pensado en esta situación y nos proporciona un elemento específico para facilitarnos la vida: el operador de encadenamiento opcional: ?.. Gracias a él podemos escribir esto:

if (usuario?.direccion?.planta?.length > 0) {
	//lo que sea...
}

Es decir, al ponerlo delante de una propiedad, ésta sólo se evalúa si el objeto precedente no es nulo (o no es "nuloso", o sea, algo que el lenguaje interpreta como nulo).

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 undefined.

Esto es equivalente a usar todos aquellos && de antes, pero mucho más claro de leer y sobre todo de escribir.

MUY IMPORTANTE: el primer objeto de la cadena debe existir y estar definido, ya que el operador necesita al menos un objeto "padre" inicial del que partir. Es decir, en nuestro ejemplo, usuario debe existir, estar definido y no ser nulo. Si se obtiene como resultado de una llamada a un servicio, por ejemplo, debemos recibir algo, aunque sea un objeto vacío, un número o lo que sea, si no recibiremos un error.

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:

var res = usuario?.haceralgo?.();

Esta sintaxis tan rara, ?.() lo que quiere decir es que, si está definida la función, llámala, y si no lo está, devuelve un undefined. De este modo podemos crear interfaces que tengan miembros opcionales, que sólo se implementan según ciertas condiciones, o podemos llamar a diferentes versiones de una API sin que rompa todo en caso de que un método no esté implementado. Muy útil.

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 usuario.hazAlgo existe y es otra cosa que no es una función (por ejemplo un array o una simple propiedad) se producirá un TypeError. Esto es una buena política porque sino, podrían darse otros errores diferentes. De este modo tenemos que ser conscientes de que vamos a llamar a una posible función.

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:

var n = 0;
var res = usuario?.haceralgo?.(n++);

...si el usuario o si la función hacerAlgo no existe y por tanto no se ejecuta, la variable n tampoco aumenta de valor ya que se detiene la evaluación de la expresión posterior a ella.

Acceso a arrays

En JavaScript una alternativa a la sintaxis . para acceder a una propiedad es mediante indexación por nombre, así:

var color = usuario.ajustes['color'];

que es equivalente a:

var color = usuario.ajustes.color;

La ventaja de la primera sintaxis es que nos permite decidir el nombre de la propiedad dinámicamente, es decir, no va escrita en el código sino que podemos recibirla en una variable:

var nomAjuste = obtenerNombreAjusteColor(); //De un servicio por ejemplo, devuelve 'color'
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 null en la propiedad ajustes o si directamente no la define, se produciría un error.

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:

var color = usuario?.ajustes?.['color'].valor;

En este caso está intentando acceder a las propiedades del objeto ajustes por su nombre.

Fíjate además que, por el cortocircuito de expresiones, si ajustes es nulo o no está definido se devuelve un undefined y ya no se intenta leer la propiedad valor del resultado tampoco (de todos modos si creemos que ajustes puede existir pero el ajuste en concreto no, convendría usar ?. también con esta última propiedad, claro).

Nos vale también para arrays normales y corrientes accedidas mediante índice:

var color = usuario?.ajustes?.[0];

De este modo si ajustes no está definido o es nulo no se producirá un error, como sí ocurriría sin este operador.

Devolver algo diferente a no definido

Finalmente, podemos combinar ese nuevo operador con el operador de unión "nulosa" que vimos el otro día para devolver un valor por defecto en estos casos, así:

var color = usuario?.ajustes?.['color'].valor ?? "#fff";

que en caso de no estar definido devolvería un color por defecto (blanco).

En resumen

El operador ?. es muy útil para escribir expresiones concisas y legibles sin arriesgarnos a que un valor nulo o no definido provoque un error en nuestro código. Su uso es extremadamente sencillo y sólo hay que conocer los pequeños detalles asociados que se explican en este artículo.

El soporte de este operador es total en los navegadores evergreen, o sea, en todos los actuales (Chrome, Firefox, Opera, Safari, Brave...), así que podemos usarlo sin miedo salvo que tengamos que dar soporte a versiones antiguas o a Internet Explorer por algún motivo.

¡Espero que te resulte útil!

José Manuel Alarcón Fundador de campusMVP, es ingeniero industrial y especialista en consultoría de empresa. Ha escrito diversos libros, habiendo publicado hasta la fecha cientos de artículos sobre informática e ingeniería en publicaciones especializadas. Microsoft lo ha reconocido como MVP (Most Valuable Professional) en desarrollo web desde el año 2004 hasta la actualidad. Puedes seguirlo en Twitter en @jm_alarcon o leer sus blog técnico o personal. Ver todos los posts de José Manuel Alarcón

¿Te ha gustado este post?
Pues espera a ver nuestro boletín mensual...

Suscríbete a la newsletter

La mejor formación online para desarrolladores como tú

Agregar comentario

Los datos anteriores se utilizarán exclusivamente para permitirte hacer el comentario y, si lo seleccionas, notificarte de nuevos comentarios en este artículo, pero no se procesarán ni se utilizarán para ningún otro propósito. Lee nuestra política de privacidad.