Los condicionales evalúan pequeñas decisiones que determinan grandes cosas.
En el capítulo anterior, Comparaciones y operadores lógicos, analizamos los comparadores (=== y !==) y los operadores booleanos (&&, || y !).
Dichos comparadores y operadores, junto con los valores booleanos presentados en el capítulo Tipos de datos básicos: boolean, number y string, son la base sobre la que se asienta la instrucción condicional if-else que se presenta en este capítulo.
Este capítulo también aborda el uso de la instrucción switch, cuyo uso, como veremos, evita largas cadenas de instrucciones if-else.
Finalmente, el capítulo expone el operador ternario de Node.JS (expresion ? instrucción : instrucción), que permite devolver un valor a partir de la evaluación de una expresión.
Índice
if-else
La instrucción if-else nos permite ejecutar una instrucción o un bloque de código en función de la evaluación de expresiones como valores booleanos:
const boolOperator1 = true
const boolOperator2 = false
if (boolOperator1 || boolOperator2) {
// Este bloque de código se ejecuta
// porque la expresión
// (boolOperator1 || boolOperator2)
// se evalúa como true
console.log("boolOperator1 o boolOperator2 es true")
}
if (boolOperator1)
// La siguiente instrucción se ejecuta
// porque la expresión (boolOperator1)
// se evalúa como true
console.log("boolOperator1 es true")
if (boolOperator1) {
// Bloque explícito: la instrucción dentro de las llaves se ejecuta
console.log("boolOperator1 es true")
} else {
// Este bloque no se ejecuta porque boolOperator1 es true
console.log("boolOperator1 no es true")
}
Como se aprecia, el uso de else es opcional. También lo es el uso de bloques de código ({ ... }) cuando la rama contiene una única instrucción —aunque por claridad es recomendable siempre usar llaves.
Node.JS permite if anidados y cadenas de else if:
const boolA = true
const boolB = false
// if anidados
// Imprime "boolA es true"
if (boolA || boolB) {
if (boolA) {
if (boolB)
console.log("boolA y boolB son true")
else
console.log("boolA es true")
} else
console.log("boolB es true")
} else
console.log("boolA y boolB son false")
// Cadena de else if
// Imprime "boolA es true"
if (boolA && boolB)
console.log("boolA y boolB son true")
else if (boolA)
console.log("boolA es true")
else if (boolB)
console.log("boolB es true")
else
console.log("boolA y boolB son false")
Al anidar if-else hay que ser cuidadoso con los bloques, porque la omisión de llaves puede producir comportamientos inesperados, como muestra el siguiente ejemplo:
const boolOperator1 = false
const boolOperator2 = true
// Aunque la indentación sugiere que se imprimirá
// "boolOperator1 es false", en realidad no se imprime nada
if (boolOperator1)
if (boolOperator2)
console.log("boolOperator1 y boolOperator2 son true")
else
console.log("boolOperator1 es false")
// El código anterior PARECE ser equivalente a este:
if (boolOperator1) {
if (boolOperator2) {
console.log("boolOperator1 y boolOperator2 son true")
}
} else {
console.log("boolOperator1 es false")
}
// Pero en realidad ES equivalente a este:
if (boolOperator1) {
if (boolOperator2) {
console.log("boolOperator1 y boolOperator2 son true")
} else {
console.log("boolOperator1 es false")
}
}
Como regla general, y para evitar este tipo de errores, define siempre bloques explícitos cuando anides instrucciones if-else.
Conversión implícita
La instrucción if evalúa su expresión en contexto booleano: antes de decidir, Node.JS convierte implícitamente el resultado entre paréntesis a boolean según las reglas vistas en Tipos de datos básicos: boolean, number y string. Ejemplos:
const nonEmptyString = "Una cadena no vacía"
const zero = 0
// En un contexto booleano (nonEmptyString) -> true
if (nonEmptyString)
console.log("nonEmptyString es una cadena no vacía")
else
console.log("nonEmptyString es una cadena vacía")
// En un contexto booleano (zero) -> false
if (zero)
console.log("zero no es 0")
else
console.log("zero es 0")
switch
Las largas cadenas de else if pueden volverse difíciles de leer. switch evalúa una expresión y la compara con distintos case:
const myNumber = 6
// Ejemplo usando if/else (imprime "myNumber es mayor de 4")
if (myNumber < 0)
console.log("myNumber es menor que 0")
else if (myNumber === 1)
console.log("myNumber es 1")
else if (myNumber === 2)
console.log("myNumber es 2")
else if (myNumber === 3)
console.log("myNumber es 3")
else if (myNumber === 4)
console.log("myNumber es 4")
else
console.log("myNumber es mayor de 4")
Con switch podemos escribirlo de forma más compacta:
const myNumber = 6
switch(myNumber) {
case 1:
console.log("myNumber es 1")
break
case 2:
console.log("myNumber es 2")
break
case 3:
console.log("myNumber es 3")
break
case 4:
console.log("myNumber es 4")
break
default:
if (myNumber < 0)
console.log("myNumber es menor que 0")
else
console.log("myNumber es mayor de 4")
}
En case no se usan automáticamente bloques {}; las instrucciones suelen terminar con break para evitar el fall-through, esto es, la ejecución continuada y accidental de las siguientes cláusulas case.
const myNumber = 1
// Ejemplo de fall-through:
// La falta de break en el primer case
// hace que este código imprima, accidentalmente,
// "myNumber es 1" y "myNumber es 2"
switch(myNumber) {
case 1:
console.log("myNumber es 1")
case 2:
console.log("myNumber es 2")
break
}
Es muy importante reseñar que switch NO realiza conversiones implícitas al comparar, como se aprecia en el siguiente ejemplo:
// emptyString es ""
const emptyString = ""
switch(emptyString) {
case false:
// ESTO NUNCA SE EJECUTARÁ
console.log("(emptyString) === false")
break
case "":
// Se ejecuta porque emptyString === ""
console.log("(emptyString) === ''")
break
}
Un comentario respecto al ejemplo anterior: Aunque el break en el último case no es estrictamente necesario (no hay más case tras el último), es buena práctica incluirlo, ya que podríamos incurrir en el error de no agregarlo en una posterior modificación del código que agregase case adicionales.
El operador ternario
El operador ternario combina evaluación condicional y elección de valor en una sola expresión:
const truthy = true
let myVariable
// Versión con if/else
if (truthy)
myVariable = "truthy es true"
else
myVariable = "truthy es false"
// Misma operación con ternario (una línea)
myVariable = truthy ? "truthy es true" : "truthy es false"
// O con mejor legibilidad en varias líneas
myVariable = truthy
? "truthy es true"
: "truthy es false"
El ternario tiene tres partes: la expresión booleana, el valor que se devolverá si la expresión se evalúa como true y el valor que se devolverá si se evalúa como false. Es, en esencia, un if-else en una sola expresión.
Los ternarios se pueden anidar, aunque la legibilidad del código puede complicarse si abusas de ellos sin la adecuada indentación:
const truthy = true
const falsy = false
let myVariable = falsy
? "falsy es true"
: truthy
? "truthy es true"
: "truthy es false"
Estos ejemplos muestran el ternario dividido en varias líneas solo por legibilidad; a efectos prácticos pueden escribirse en una sola línea (más compacta, pero menos legible).
Lo que hemos conseguido
En este capítulo —el último del bloque de sintaxis básica de Node.JS— has aprendido a usar if-else, switch y el operador ternario, y conoces sus peculiaridades (anidamiento, fall-through en switch, y conversión implícita en contextos booleanos).
Qué viene a continuación
¡Enhorabuena! Has completado el bloque de sintaxis básica y estás listo para el siguiente bloque, que introduce estructuras de iteración, funciones, arrays y objetos. Antes, practicaremos con ejercicios y aprenderemos a depurar en VSCode en el próximo capítulo: Depuración de Node.JS en Visual Studio Code.