12 de agosto de 2022

Operadores Lógicos

Hay cuatro operadores lógicos en JavaScript: || (O), && (Y), ! (NO), ?? (Fusión de nulos). Aquí cubrimos los primeros tres, el operador ?? se verá en el siguiente artículo.

Aunque sean llamados lógicos, pueden ser aplicados a valores de cualquier tipo, no solo booleanos. El resultado también puede ser de cualquier tipo.

Veamos los detalles.

|| (OR)

El operador OR se representa con dos símbolos de linea vertical:

result = a || b;

En la programación clásica, el OR lógico esta pensado para manipular solo valores booleanos. Si cualquiera de sus argumentos es true, retorna true, de lo contrario retorna false.

En JavaScript, el operador es un poco más complicado y poderoso. Pero primero, veamos qué pasa con los valores booleanos.

Hay cuatro combinaciones lógicas posibles:

alert(true || true); // true (verdadero)
alert(false || true); // true
alert(true || false); // true
alert(false || false); // false (falso)

Como podemos ver, el resultado es siempre true excepto cuando ambos operandos son false.

Si un operando no es un booleano, se lo convierte a booleano para la evaluación.

Por ejemplo, el número 1 es tratado como true, el número 0 como false:

if (1 || 0) { // Funciona como if( true || false )
  alert("valor verdadero!");
}

La mayoría de las veces, OR || es usado en una declaración if para probar si alguna de las condiciones dadas es true.

Por ejemplo:

let hour = 9;

if (hour < 10 || hour > 18) {
  alert( 'La oficina esta cerrada.' );
}

Podemos pasar mas condiciones:

let hour = 12;
let isWeekend = true;

if (hour < 10 || hour > 18 || isWeekend) {
  alert("La oficina esta cerrada."); // Es fin de semana
}

OR "||" encuentra el primer valor verdadero

La lógica descrita arriba es algo clásica. Ahora, mostremos las características “extra” de JavaScript.

El algoritmo extendido trabaja de la siguiente forma.

Dado múltiples valores aplicados al operador OR:

result = value1 || value2 || value3;

El operador OR || realiza lo siguiente:

  • Evalúa los operandos de izquierda a derecha.
  • Para cada operando, convierte el valor a booleano. Si el resultado es true, se detiene y retorna el valor original de ese operando.
  • Si todos los operandos han sido evaluados (todos eran false), retorna el ultimo operando.

Un valor es retornado en su forma original, sin la conversión.

En otras palabras, una cadena de OR "||" devuelve el primer valor verdadero o el último si ningún verdadero es encontrado.

Por ejemplo:

alert(1 || 0); // 1 (1 es un valor verdadero)

alert(null || 1); // 1 (1 es el primer valor verdadero)
alert(null || 0 || 1); // 1 (el primer valor verdadero)

alert(undefined || null || 0); // 0 (todos son valores falsos, retorna el último valor)

Esto brinda varios usos interesantes comparados al “OR puro, clásico, de solo booleanos”.

  1. Obtener el primer valor verdadero de una lista de variables o expresiones.

    Por ejemplo, tenemos las variables firstName, lastName y nickName, todas opcionales (pueden ser undefined o tener valores falsos).

    Usemos OR || para elegir el que tiene los datos y mostrarlo (o anónimo si no hay nada configurado):

    let firstName = "";
    let lastName = "";
    let nickName = "SuperCoder";
    
    alert( firstName || lastName || nickName || "Anonymous"); // SuperCoder

    Si todas las variables fueran falsas, aparecería "Anonymous".

  2. Evaluación del camino más corto.

    Otra característica del operador OR || es la evaluación de “el camino más corto” o “cortocircuito”.

    Esto significa que || procesa sus argumentos hasta que se alcanza el primer valor verdadero, y ese valor se devuelve inmediatamente sin siquiera tocar el otro argumento.

    La importancia de esta característica se vuelve obvia si un operando no es solo un valor sino una expresión con un efecto secundario, como una asignación de variable o una llamada a función.

    En el siguiente ejemplo, solo se imprime el segundo mensaje:

    true || alert("not printed");
    false || alert("printed");

    En la primera línea, el operador OR || detiene la evaluación inmediatamente después de ver que es verdadera, por lo que la alerta no se ejecuta.

    A veces se usa esta función para ejecutar comandos solo si la condición en la parte izquierda es falsa.

&& (AND)

El operador AND es representado con dos ampersands &&:

result = a && b;

En la programación clásica, AND retorna true si ambos operandos son valores verdaderos y false en cualquier otro caso.

alert(true && true); // true
alert(false && true); // false
alert(true && false); // false
alert(false && false); // false

Un ejemplo con if:

let hour = 12;
let minute = 30;

if (hour == 12 && minute == 30) {
  alert("La hora es 12:30");
}

Al igual que con OR, cualquier valor es permitido como operando de AND:

if (1 && 0) { // evaluado como true && false
  alert( "no funcionará porque el resultado es un valor falso" );
}

AND “&&” encuentra el primer valor falso

Dado múltiples valores aplicados al operador AND:

result = value1 && value2 && value3;

El operador AND && realiza lo siguiente:

  • Evalúa los operandos de izquierda a derecha.
  • Para cada operando, los convierte a un booleano. Si el resultado es false, se detiene y retorna el valor original de dicho operando.
  • Si todos los operandos han sido evaluados (todos fueron valores verdaderos), retorna el último operando.

En otras palabras, AND retorna el primer valor falso o el último valor si ninguno fue encontrado.

Las reglas anteriores son similares a las de OR. La diferencia es que AND retorna el primer valor falso mientras que OR retorna el primer valor verdadero.

Ejemplo:

// si el primer operando es un valor verdadero,
// AND retorna el segundo operando:
alert(1 && 0); // 0
alert(1 && 5); // 5

// si el primer operando es un valor falso,
// AND lo retorna. El segundo operando es ignorado
alert(null && 5); // null
alert(0 && "cualquier valor"); // 0

También podemos pasar varios valores de una vez. Observa como el primer valor falso es retornado:

alert(1 && 2 && null && 3); // null

Cuando todos los valores son verdaderos, el último valor es retornado:

alert(1 && 2 && 3); // 3, el último.
La precedencia de AND && es mayor que la de OR ||

La precedencia del operador AND && es mayor que la de OR ||.

Así que el código a && b || c && d es básicamente el mismo que si la expresiones && estuvieran entre paréntesis: (a && b) || (c && d)

No remplace if con || ni &&

A veces, la gente usa el operador AND && como una “forma más corta de escribir if”.

Por ejemplo:

let x = 1;

(x > 0) && alert("¡Mayor que cero!");

La acción en la parte derecha de && sería ejecutada sólo si la evaluación la alcanza. Eso es, solo si (x > 0) es verdadero.

Así que básicamente tenemos un análogo para:

let x = 1;

if (x > 0) alert("Mayor que cero!");

Aunque la variante con && parece más corta, if es más obvia y tiende a ser un poco más legible. Por lo tanto, recomendamos usar cada construcción para su propósito: use if si queremos si y use&&si queremos AND.

! (NOT)

El operador booleano NOT se representa con un signo de exclamación !.

La sintaxis es bastante simple:

result = !value;

El operador acepta un solo argumento y realiza lo siguiente:

  1. Convierte el operando al tipo booleano: true/false.
  2. Retorna el valor contrario.

Por ejemplo:

alert(!true); // false
alert(!0); // true

Un doble NOT !! es a veces usado para convertir un valor al tipo booleano:

alert(!!"cadena de texto no vacía"); // true
alert(!!null); // false

Eso es, el primer NOT convierte el valor a booleano y retorna el inverso, y el segundo NOT lo invierte de nuevo. Al final, tenemos una simple conversión a booleano.

Hay una manera un poco mas prolija de realizar lo mismo – una función integrada Boolean:

alert(Boolean("cadena de texto no vacía")); // true
alert(Boolean(null)); // false

La precedencia de NOT ! es la mayor de todos los operadores lógicos, así que siempre se ejecuta primero, antes que && o ||.

Tareas

importancia: 5

¿Cuál será la salida del siguiente código?

alert( null || 2 || undefined );

La respuesta es 2, ese es el primer valor verdadero.

alert( null || 2 || undefined );
importancia: 3

¿Cuál será la salida del siguiente código?

alert( alert(1) || 2 || alert(3) );

La repuesta: primero 1, después 2.

alert( alert(1) || 2 || alert(3) );

La llamada a alert no retorna un valor. O, en otras palabras, retorna undefined.

  1. El primer OR || evalúa el operando de la izquierda alert(1). Eso muestra el primer mensaje con 1.
  2. El alert retorna undefined, por lo que OR se dirige al segundo operando buscando un valor verdadero.
  3. El segundo operando 2 es un valor verdadero, por lo que se detiene la ejecución, se retorna 2 y es mostrado por el alert exterior.

No habrá 3 debido a que la evaluación no alcanza a alert(3).

importancia: 5

¿Cuál será la salida del siguiente código?

alert( 1 && null && 2 );

La respuesta: null, porque es el primer valor falso de la lista.

alert(1 && null && 2);
importancia: 3

¿Cuál será la salida del siguiente código?

alert( alert(1) && alert(2) );

La respuesta: 1 y después undefined.

alert( alert(1) && alert(2) );

La llamada a alert retorna undefined (solo muestra un mensaje, así que no hay un valor que retornar relevante)

Debido a ello, && evalúa el operando de la izquierda (imprime 1) e inmediatamente se detiene porque undefined es un valor falso. Como && busca un valor falso y lo retorna, terminamos.

importancia: 5

¿Cuál será el resultado?

alert( null || 2 && 3 || 4 );

La respuesta: 3.

alert( null || 2 && 3 || 4 );

La precedencia de AND && es mayor que la de ||, así que se ejecuta primero.

El resultado de 2 && 3 = 3, por lo que la expresión se convierte en:

null || 3 || 4

Ahora el resultado será el primer valor verdadero: 3.

importancia: 3

Escribe una condición “if” para comprobar que age(edad) está entre 14 y 90 inclusive.

“Inclusive” significa que age puede llegar a ser uno de los extremos, 14 o 90.

if (age >= 14 && age <= 90)
importancia: 3

Escribe una condición if para comprobar que age NO está entre 14 y 90 inclusive.

Crea dos variantes: la primera usando NOT !, y la segunda sin usarlo.

La primer variante:

if (!(age >= 14 && age <= 90))

La segunda variante:

if (age < 14 || age > 90)
importancia: 5

¿Cuáles de estos alerts va a ejecutarse?

¿Cuáles serán los resultados de las expresiones dentro de if(...)?

if (-1 || 0) alert( "primero" );
if (-1 && 0) alert( "segundo" );
if (null || -1 && 1) alert( "tercero" );

La respuesta: el primero y el tercero serán ejecutados.

Detalles:

// Corre.
// El resultado de -1 || 0 = -1, valor verdadero
if (-1 || 0) alert( "primero" );

// No corre.
// -1 && 0 = 0, valor falso
if (-1 && 0) alert( "segundo" );

// Se ejecuta
// El operador && tiene mayor precedencia que ||
// Así que -1 && 1 se ejecuta primero, dándonos la cadena:
// null || -1 && 1  ->  null || 1  ->  1
if (null || -1 && 1) alert( "tercero" );
importancia: 3

Escribe un código que pregunte por el inicio de sesión con propmt.

Si el visitante ingresa "Admin", entonces prompt(pregunta) por una contraseña, si la entrada es una linea vacía o Esc – muestra “Cancelado.”, si es otra cadena de texto – entonces muestra “No te conozco”.

La contraseña se comprueba de la siguiente manera:

  • Si es igual a “TheMaster”, entonces muestra “Bienvenido!”,
  • Si es otra cadena de texto – muetra “Contraseña incorrecta”,
  • Para una cadena de texto vacía o una entrada cancelada, muestra “Cancelado.”

El esquema:

Por favor usa bloques anidados de if. Piensa en la legibilidad general del código.

Pista: si se le pasa una entrada vacía a un prompt, retorna una cadena de texto vacía ''. Presionando ESC durante un prompt retorna null.

Ejecutar el demo

let userName = prompt("Quién está ahí?", "");

if (userName == "Admin") {

    let pass = prompt("¿Contraseña?", "");

    if (pass === "TheMaster") {
  alert( "Bienvenido!" );
    } else if (pass === "" || pass === null) {
  alert( "Cancelado." );
    } else {
  alert( "Contraseña incorrecta" );
    }

} else if (userName === "" || userName === null) {
    alert( "Canceledo" );
} else {
    alert( "No te conozco" );
}

Nota las sangrías verticales dentro de los bloques if. Técnicamente no son necesarias, pero facilitan la lectura del código.

Mapa del Tutorial