Command Palette

Search for a command to run...

Operadores de Comparación e Igualdad en JavaScript

Entiende la comparación de valores con ===, ==, >, <, >=, <=. Aprende por qué === es más seguro que ==, y evita bugs comunes de comparación.

Lectura: 13 min
Nivel: Intermedio

TL;DR - Resumen rápido

  • === (igualdad estricta) compara valor Y tipo sin coerción. == (igualdad suelta) hace coerción de tipos
  • SIEMPRE usa === y !== en lugar de == y != para evitar bugs de coerción inesperada
  • Operadores relacionales: > < >= <= comparan números. Con strings, comparan alfabéticamente (Unicode)
  • null == undefined es true, pero null === undefined es false. Son los únicos valores == sin ser ===
  • Objetos y arrays se comparan por referencia, no por contenido. {} === {} es false (referencias diferentes)
  • NaN no es igual a nada, ni a sí mismo: NaN === NaN es false. Usa Number.isNaN() para verificar NaN
  • Object.is() es como === pero distingue -0 de +0, y considera NaN === NaN true

Introducción a Operadores de Comparación

Los operadores de comparación permiten comparar dos valores y retornan un booleano (true o false). JavaScript tiene operadores de igualdad (===, ==, !==, !=) que verifican si dos valores son iguales o diferentes, y operadores relacionales (>, <, >=, <=) que verifican orden o magnitud. Estos operadores son fundamentales para condiciones, validaciones, y control de flujo en tu código.

La distinción más importante es entre igualdad estricta (===) e igualdad suelta (==). La igualdad estricta compara valor Y tipo sin hacer conversiones - 5 === "5" es false porque son tipos diferentes. La igualdad suelta hace coerción de tipos antes de comparar - 5 == "5" es true porque convierte el string a número. Esta coerción causa bugs sutiles, por eso la mejor práctica universal es SIEMPRE usar === y nunca usar ==.

Por Qué Existen Dos Tipos de Igualdad

JavaScript heredó == de lenguajes antiguos donde la coerción automática era común. === se añadió después para permitir comparación sin coerción, más predecible. Hoy en día, == se considera un error de diseño histórico - casi nunca quieres comparación con coerción. Lenguajes modernos como Python solo tienen un operador de igualdad que funciona como ===. En JavaScript moderno, trata == como obsoleto y usa === siempre.

Igualdad Estricta (===): Sin Coerción

El operador de igualdad estricta (===) compara dos valores sin hacer conversión de tipos. Retorna true solo si ambos valores tienen el mismo tipo Y el mismo valor. 5 === 5 es true, pero 5 === "5" es false porque son tipos diferentes. También existe !== que retorna true si los valores son diferentes en valor O en tipo. Esta es la forma segura y predecible de comparar valores.

igualdad-estricta.js
Loading code...

Con ===, los valores deben ser del mismo tipo y tener el mismo valor para ser iguales. Números se comparan por valor, strings por contenido carácter por carácter, booleanos por valor. null solo es === a null, undefined solo es === a undefined. NaN no es === a nada (ni a sí mismo). Objetos y arrays se comparan por referencia - dos objetos con mismo contenido no son === si son instancias diferentes.

=== Es La Forma Correcta de Comparar

La mejor práctica universal en JavaScript moderno es SIEMPRE usar === y !== para comparaciones. Son más rápidos (sin coerción), más predecibles, y previenen bugs sutiles. No hay situaciones legítimas donde necesites ==. Si quieres verificar null O undefined juntos, usa explícitamente: value === null || value === undefined. ESLint y Prettier te avisarán si usas ==. Trata === como el único operador de igualdad que existe.

Igualdad Suelta (==): Con Coerción

El operador de igualdad suelta (==) compara dos valores después de convertirlos a un tipo común. JavaScript tiene reglas complejas de coerción para ==: strings se convierten a números, booleanos se convierten a números (true es 1, false es 0), null == undefined es true por regla especial. Estas conversiones automáticas causan comportamientos contraintuitivos y bugs sutiles. Por eso == se considera mala práctica y debes evitarlo.

igualdad-suelta.js
Loading code...

El operador == hace coerción con reglas complejas: (1) Si tipos son iguales, compara como ===, (2) null == undefined es true, pero no son == a otros valores, (3) Si uno es número y otro string, convierte string a número, (4) Si uno es boolean, lo convierte a número (true=1, false=0), (5) Objetos se convierten con valueOf() o toString(). Estas reglas causan resultados sorprendentes como "0" == false siendo true. Evita == completamente.

Por Qué == Es Peligroso

Las reglas de coerción de == son tan complejas que incluso programadores experimentados se equivocan. "0" == false es true, pero "0" == 0 también es true, entonces podrías pensar que false == 0 es true (correcto), pero [] == false también es true (!). Estos comportamientos inconsistentes causan bugs difíciles de detectar. No hay ventaja en usar == - solo añade complejidad y riesgo. Usa === siempre.

=== vs ==: Diferencias Clave y Cuándo Usar Cada Uno

La diferencia fundamental es que === compara sin coerción de tipos, mientras == hace coerción antes de comparar. === es más estricto, más rápido, más predecible. == es más permisivo pero impredecible. En código profesional moderno, se usa === exclusivamente. El único caso histórico donde algunos usan == es para verificar null y undefined juntos (value == null), pero incluso esto es mejor hacerlo explícitamente con === y ||.

estricta-vs-suelta.js
Loading code...

Diferencias principales: (1) === compara tipo y valor, == solo valor después de coerción, (2) === es más rápido (sin conversiones), == más lento, (3) === es predecible, == tiene reglas complejas, (4) === nunca causa bugs de coerción, == es fuente común de bugs, (5) === es estándar en código moderno, == se considera obsoleto. La única ventaja de == es brevedad al verificar null/undefined, pero no vale el riesgo. Usa === siempre.

Operadores Relacionales: >, <, >=, <=

Los operadores relacionales (>, <, >=, <=) verifican si un valor es mayor, menor, mayor o igual, o menor o igual que otro. Con números, funcionan como esperarías - 10 > 5 es true. Con strings, comparan alfabéticamente usando valores Unicode - "b" > "a" es true. Si comparas tipos diferentes, JavaScript hace coerción a número, lo que puede dar resultados inesperados.

operadores-relacionales.js
Loading code...

Los operadores relacionales funcionan bien con números. Con strings, comparan carácter por carácter usando valores Unicode (case-sensitive: "A" < "a" porque mayúsculas tienen códigos menores). Si comparas número con string, convierte a número: "10" > 5 es true. >= y <= combinan comparación con igualdad: 5 >= 5 es true. Con tipos mixtos, la coerción puede dar resultados inesperados - valida tipos antes de comparar.

Comparación de Strings: Unicode, No Alfabética

Los strings se comparan por código Unicode, no alfabéticamente: "Z" < "a" es true (mayúsculas antes que minúsculas). Para comparación alfabética case-insensitive, usa .toLowerCase(): str1.toLowerCase() > str2.toLowerCase(). Para comparación localizada (con acentos, ñ, etc.), usa localeCompare(): str1.localeCompare(str2). Unicode hace que "10" < "2" sea true (compara carácter por carácter: "1" < "2").

Comparación de Strings: Unicode y Casos Especiales

La comparación de strings en JavaScript se basa en valores Unicode (UTF-16), no en orden alfabético tradicional. Cada carácter tiene un código numérico, y la comparación se hace carácter por carácter de izquierda a derecha. Esto causa comportamientos inesperados: mayúsculas vienen antes que minúsculas, números como strings se ordenan lexicográficamente (no numéricamente), y caracteres especiales tienen posiciones específicas en la tabla Unicode.

comparacion-strings.js
Loading code...

Los strings se comparan carácter por carácter usando códigos Unicode. Mayúsculas (65-90) vienen antes que minúsculas (97-122), por eso "Z" < "a". Números como strings se comparan lexicográficamente: "10" < "2" porque compara primero "1" vs "2". Para comparación case-insensitive, convierte a minúsculas. Para comparación numérica de strings numéricos, convierte a Number(). Para comparación localizada (alfabetos con acentos), usa localeCompare().

Comparación de Objetos: Por Referencia, No por Contenido

Los objetos y arrays se comparan por referencia, no por contenido. Dos objetos son iguales solo si son la MISMA instancia (apuntan a la misma ubicación en memoria). Dos objetos con propiedades idénticas no son === si son instancias diferentes. Esto es diferente a primitivos que se comparan por valor. Para comparar contenido de objetos, necesitas comparación profunda manual o librerías.

comparacion-objetos.js
Loading code...

Objetos y arrays se comparan por referencia. === es false porque son dos instancias diferentes, aunque tengan mismo contenido. Solo si dos variables apuntan al MISMO objeto, son ===. Esto aplica a arrays, objetos, funciones, fechas, etc. Para comparar contenido (igualdad profunda), necesitas comparar propiedad por propiedad recursivamente. JSON.stringify() funciona para objetos simples pero falla con funciones, undefined, símbolos, y orden de propiedades.

Comparación Profunda de Objetos

Para comparar contenido de objetos, usa librerías como Lodash (_.isEqual) o implementa comparación profunda recursiva. JSON.stringify() funciona solo con objetos simples sin funciones, undefined, o símbolos, y es sensible al orden de propiedades. Para arrays simples de primitivos, puedes convertir a string: arr1.join() === arr2.join() (pero falla con arrays anidados). En tests, usa assert.deepEqual() o expect().toEqual().

Casos Especiales: NaN, null, undefined, -0

JavaScript tiene varios casos especiales en comparaciones que pueden causar confusión. NaN (Not a Number) no es igual a nada, ni siquiera a sí mismo - NaN === NaN es false. null y undefined son == pero no ===. -0 y +0 son === aunque sean valores diferentes. Infinity es === a Infinity. Estos casos especiales requieren métodos específicos de verificación para manejarlos correctamente.

casos-especiales.js
Loading code...

Casos especiales importantes: (1) NaN === NaN es false - usa Number.isNaN() para verificar NaN, (2) null == undefined es true pero null === undefined es false, (3) -0 === +0 es true aunque matemáticamente sean diferentes, (4) Infinity === Infinity es true, (5) Objetos vacíos nunca son iguales: === es false. Estos casos requieren verificaciones especiales con Number.isNaN(), Object.is(), o comparación explícita con === null.

NaN: El Valor Que No Se Iguala a Sí Mismo

NaN es único porque no es igual a nada, ni a sí mismo: NaN === NaN retorna false. Esto viene de la especificación IEEE 754 para números flotantes. No puedes usar === para verificar NaN - debes usar Number.isNaN(valor). El método global isNaN() es diferente y menos confiable - convierte a número primero, así que isNaN("hola") es true. Usa Number.isNaN() que solo retorna true para NaN real.

Object.is(): Comparación Más Estricta que ===

Object.is() es un método moderno (ES6) que hace comparación similar a === pero con dos diferencias: distingue +0 de -0 (Object.is(+0, -0) es false), y considera NaN igual a NaN (Object.is(NaN, NaN) es true). Es la comparación más estricta y matemáticamente correcta de JavaScript. Úsalo cuando necesites distinguir estos casos edge, pero para la mayoría de comparaciones === es suficiente.

object-is.js
Loading code...

Object.is() es como === pero más correcto matemáticamente: (1) Distingue +0 de -0 (=== los trata como iguales), (2) Considera NaN === NaN como true (=== lo trata como false), (3) En todo lo demás funciona igual que ===. Úsalo cuando estos casos edge importan (cálculos científicos, claves de Map). Para comparaciones normales, === es suficiente y más común. Object.is() no hace coerción de tipos como ==.

Resumen: Operadores de Comparación

Operadores principales:

  • === !== para igualdad estricta sin coerción (SIEMPRE usa estos)
  • == != para igualdad suelta con coerción (NUNCA uses estos)
  • > < >= <= para comparar magnitud de números y orden de strings
  • Object.is() para comparación perfecta que distingue +0/-0 y NaN
  • Objetos se comparan por referencia, no por contenido

Mejores prácticas:

  • SIEMPRE usa === y !==, NUNCA uses == o !=
  • Para NaN usa Number.isNaN(), no comparación directa
  • Para null/undefined usa === null o === undefined explícitamente
  • Strings se comparan por Unicode, usa localeCompare() para alfabético
  • Para comparar objetos por contenido, usa librerías o comparación manual