Ir al contenido principal

Operadores de comparación

Introducción

Los operadores de comparación son herramientas fundamentales en JavaScript que nos permiten comparar valores y determinar relaciones entre ellos. Estas comparaciones devuelven siempre un valor booleano (true o false), lo que los hace esenciales para la toma de decisiones en nuestros programas. Entender cómo funcionan estos operadores y sus diferencias es crucial para escribir código confiable y evitar errores de lógica comunes que pueden ser difíciles de detectar.

En este artículo exploraremos todos los operadores de comparación disponibles en JavaScript, sus particularidades y cómo utilizarlos correctamente en diferentes situaciones. Además, veremos casos especiales y buenas prácticas que nos ayudarán a evitar comportamientos inesperados en nuestro código.

Igualdad simple (==) vs. igualdad estricta (===)

JavaScript proporciona dos operadores diferentes para comprobar si dos valores son iguales: la igualdad simple (==) y la igualdad estricta (===). La diferencia entre ambos es fundamental para entender el comportamiento de JavaScript.

Igualdad simple (==)

El operador de igualdad simple compara dos valores después de convertirlos al mismo tipo. Esto significa que JavaScript intentará hacer una conversión automática de tipos antes de realizar la comparación.

// Ejemplos de igualdad simple
console.log(5 == "5");         // true, porque "5" se convierte a número
console.log(0 == false);       // true, porque false se convierte a 0
console.log("" == false);      // true, porque ambos se convierten a 0
console.log(null == undefined); // true, caso especial en JavaScript

Como puedes ver, este operador puede producir resultados que parecen ilógicos a primera vista, pero que tienen sentido cuando entendemos las reglas de conversión de tipos de JavaScript.

Igualdad estricta (===)

El operador de igualdad estricta compara dos valores sin realizar conversión de tipos. Para que la comparación devuelva true, ambos valores deben ser del mismo tipo y tener el mismo valor.

// Ejemplos de igualdad estricta
console.log(5 === "5");         // false, son de tipos diferentes
console.log(0 === false);       // false, son de tipos diferentes
console.log("" === false);      // false, son de tipos diferentes
console.log(null === undefined); // false, son de tipos diferentes

// Ejemplos donde sí son iguales
console.log(5 === 5);           // true
console.log("hola" === "hola"); // true
console.log(true === true);     // true

La igualdad estricta proporciona resultados más predecibles y suele ser la opción recomendada en la mayoría de los casos.

Desigualdad simple (!=) vs. desigualdad estricta (!==)

De manera similar a los operadores de igualdad, JavaScript proporciona dos operadores para comprobar si dos valores son diferentes:

Desigualdad simple (!=)

Comprueba si dos valores son diferentes después de la conversión de tipos:

console.log(5 != "5");         // false, porque después de la conversión son iguales
console.log(0 != false);       // false, porque después de la conversión son iguales
console.log("" != false);      // false, porque después de la conversión son iguales
console.log(null != undefined); // false, porque después de la conversión son iguales

Desigualdad estricta (!==)

Comprueba si dos valores son diferentes sin realizar conversión de tipos:

console.log(5 !== "5");         // true, son de tipos diferentes
console.log(0 !== false);       // true, son de tipos diferentes
console.log("" !== false);      // true, son de tipos diferentes
console.log(null !== undefined); // true, son de tipos diferentes

Operadores de relación (>, <, >=, <=)

Estos operadores comparan dos valores para determinar sus relaciones de orden:

  • > (mayor que)
  • < (menor que)
  • >= (mayor o igual que)
  • <= (menor o igual que)
// Ejemplos con números
console.log(5 > 3);   // true
console.log(5 < 3);   // false
console.log(5 >= 5);  // true
console.log(5 <= 3);  // false

// JavaScript convierte strings a números cuando es posible
console.log(5 > "3");  // true, "3" se convierte a 3
console.log("5" < 10); // true, "5" se convierte a 5

Comparación de strings

Cuando comparamos strings, JavaScript realiza una comparación lexicográfica (como en un diccionario), carácter por carácter según sus valores Unicode:

console.log("a" < "b");       // true, 'a' viene antes que 'b' en Unicode
console.log("abc" < "abd");   // true, compara carácter por carácter
console.log("10" < "2");      // true, '1' viene antes que '2' en Unicode
console.log("z" < "A");       // false, las mayúsculas tienen valores menores que las minúsculas

Es importante notar que comparar "10" < "2" da true porque compara carácter por carácter, y "1" es menor que "2" en valores Unicode. Si queremos comparar estos valores como números, debemos convertirlos explícitamente:

console.log(Number("10") < Number("2")); // false, ahora compara 10 con 2

Comparación de diferentes tipos de datos

Cuando comparamos valores de diferentes tipos, JavaScript aplica reglas de conversión específicas:

// Número vs String
console.log(5 > "3");      // true, convierte "3" a número
console.log("5" > 3);      // true, convierte "5" a número

// Booleanos con otros valores
console.log(true > 0);     // true, true se convierte a 1
console.log(false < 1);    // true, false se convierte a 0

// Arrays se convierten a strings antes de comparar
console.log([1, 2] < [1, 3]);  // true, se compara "1,2" con "1,3"
console.log([10] > [2]);      // false, se compara "10" con "2" como strings

Comparación de objetos y arrays

Cuando comparamos objetos y arrays con los operadores == o ===, JavaScript compara referencias de memoria, no contenido:

let obj1 = {nombre: "Ana"};
let obj2 = {nombre: "Ana"};
let obj3 = obj1;

console.log(obj1 == obj2);   // false, diferentes referencias
console.log(obj1 === obj2);  // false, diferentes referencias
console.log(obj1 == obj3);   // true, misma referencia
console.log(obj1 === obj3);  // true, misma referencia

// Lo mismo ocurre con arrays
let arr1 = [1, 2, 3];
let arr2 = [1, 2, 3];
let arr3 = arr1;

console.log(arr1 == arr2);   // false, diferentes referencias
console.log(arr1 === arr2);  // false, diferentes referencias
console.log(arr1 == arr3);   // true, misma referencia
console.log(arr1 === arr3);  // true, misma referencia

Para comparar el contenido de objetos o arrays, necesitamos estrategias alternativas:

// Para arrays simples podemos usar .toString()
console.log(arr1.toString() === arr2.toString()); // true

// Para objetos, podemos usar JSON.stringify() (con limitaciones)
console.log(JSON.stringify(obj1) === JSON.stringify(obj2)); // true

Estas técnicas tienen limitaciones y no funcionan en casos complejos o con objetos que contienen métodos o propiedades no serializables.

Casos particulares (null, undefined, NaN)

Los valores null, undefined y NaN merecen una atención especial:

null y undefined

console.log(null == undefined);  // true, caso especial
console.log(null === undefined); // false, son de tipos diferentes

console.log(null == 0);          // false
console.log(undefined == 0);     // false

NaN (Not a Number)

NaN es un valor especial que representa un error en operaciones numéricas. Una característica importante de NaN es que no es igual a ningún valor, ni siquiera a sí mismo:

console.log(NaN == NaN);   // false
console.log(NaN === NaN);  // false

// Para verificar si un valor es NaN, usamos la función isNaN() o Number.isNaN()
console.log(isNaN(NaN));         // true
console.log(Number.isNaN(NaN));  // true

// Diferencia entre isNaN() y Number.isNaN()
console.log(isNaN("hola"));      // true, convierte a número y da NaN
console.log(Number.isNaN("hola")); // false, no convierte, solo verifica si es NaN

Buenas prácticas en comparaciones

  1. Utiliza igualdad estricta (===) por defecto

    La igualdad estricta evita comportamientos inesperados causados por la conversión automática de tipos:

    // Recomendado
    if (edad === 18) {
        console.log("Tienes exactamente 18 años");
    }
    
    // Evitar
    if (edad == 18) {
        // Esto también sería true si edad fuera "18"
    }
    
  2. Compara con el mismo tipo de datos

    Si necesitas comparar valores de diferentes tipos, conviértelos explícitamente:

    // Recomendado
    if (Number(inputEdad) > 18) {
        console.log("Eres mayor de edad");
    }
    
    // Evitar
    if (inputEdad > 18) {
        // Comportamiento impredecible si inputEdad es un string
    }
    
  3. Ten cuidado con los valores falsy

    JavaScript considera varios valores como "falsy": 0, "", null, undefined, NaN y false. Utiliza comparaciones explícitas cuando sea necesario:

    // Puede dar resultados inesperados
    if (valor) {
        // No se ejecutará si valor es 0 o ""
    }
    
    // Mejor, más específico
    if (valor !== null && valor !== undefined && valor !== "") {
        // Más claro en intención
    }
    
  4. Verifica la existencia de propiedades en objetos

    Para propiedades que podrían no existir, utiliza el operador de encadenamiento opcional:

    // ES2020+ (moderno)
    if (usuario?.direccion?.ciudad === "Madrid") {
        // Seguro incluso si usuario o direccion son undefined
    }
    
    // Pre-ES2020
    if (usuario && usuario.direccion && usuario.direccion.ciudad === "Madrid") {
        // Más verboso pero también seguro
    }
    

Resumen

Los operadores de comparación en JavaScript nos permiten evaluar relaciones entre valores y son fundamentales para la lógica de nuestros programas. La diferencia principal entre los operadores de igualdad simple (==, !=) y estricta (===, !==) radica en la conversión automática de tipos, siendo generalmente preferible utilizar los operadores estrictos.

Al trabajar con diferentes tipos de datos, especialmente objetos, arrays y valores especiales como null, undefined y NaN, debemos ser conscientes de las reglas específicas que aplica JavaScript. Siguiendo las buenas prácticas mencionadas, podremos escribir código más predecible y evitar errores comunes relacionados con las comparaciones.

En los próximos artículos, exploraremos los operadores lógicos que nos permitirán combinar varias comparaciones y construir expresiones de condición más complejas para nuestros programas.