O operador == tenta ser prestativo. Antes de comparar dois valores, ele os converte para o mesmo tipo. Essa conversão automática é a coerção de tipo.
Por exemplo, se você compara o número 5 com a string "5", o JavaScript pensa: "Esses parecem similares. Deixa eu converter e verificar." Então 5 == "5" retorna true.
Como Funciona
Quando você escreve x == y, o JavaScript pergunta:
x e y são do mesmo tipo? → Compara diretamente
- São tipos diferentes? → Converte um ou ambos para combinar, depois compara
Essa conversão automática pode ser útil, mas também pode causar resultados inesperados.
O Algoritmo de Igualdade Abstrata
Aqui está o algoritmo completo da especificação ECMAScript. Ao comparar x == y:
Mesmo Tipo?
Se x e y são do mesmo tipo, realiza comparação de igualdade estrita (===).
snippetJavaScript
5 == 5 // Mesmo tipo (number), compara diretamente → true"hello" == "hello" // Mesmo tipo (string), compara diretamente → true
null e undefined
Se x é null e y é undefined (ou vice-versa), retorna true.
snippetJavaScript
null == undefined // true (caso especial!)undefined == null // true
Number e String
Se um é Number e o outro é String, converte a String para Number.
snippetJavaScript
5 == "5" // "5" → 5, depois 5 == 5 → true0 == "" // "" → 0, depois 0 == 0 → true42 == "42" // "42" → 42, depois 42 == 42 → true
BigInt e String
Se um é BigInt e o outro é String, converte a String para BigInt.
snippetJavaScript
10n == "10" // "10" → 10n, depois 10n == 10n → true
Conversão Booleana
Se qualquer valor é Boolean, converte para Number (true → 1, false → 0).
snippetJavaScript
true == 1 // true → 1, depois 1 == 1 → truefalse == 0 // false → 0, depois 0 == 0 → truetrue == "1" // true → 1, depois 1 == "1" → 1 == 1 → true
Objeto para Primitivo
Se um é Object e o outro é String, Number, BigInt ou Symbol, converte o Object para primitivo usando ToPrimitive.
snippetJavaScript
[1] == 1 // [1] → "1" → 1, depois 1 == 1 → true[""] == 0 // [""] → "" → 0, depois 0 == 0 → true
BigInt e Number
Se um é BigInt e o other é Number, compara seus valores matemáticos.
snippetJavaScript
10n == 10 // Compara valores: 10 == 10 → true10n == 10.5 // 10 !== 10.5 → false
Sem Correspondência
Se nenhuma regra acima se aplica, retorna false.
snippetJavaScript
null == 0 // false (null só iguala undefined)undefined == 0 // falseSymbol() == Symbol() // false (Symbols são sempre únicos)
Visual: A Árvore de Decisão da Coerção
snippettext
x == y │ ┌────────────┴────────────┐ ▼ ▼ Mesmo tipo? Tipos diferentes? │ │ SIM SIM │ │ ▼ ▼ Compara valores ┌────────┴────────┐ (como ===) │ │ ▼ ▼ null == undefined? Aplica regras │ de coerção SIM │ │ ▼ ▼ Converte tipos true e compara novamente
Tabela Completa de Regras de Coerção
| Tipo de x | Tipo de y | Coerção Aplicada |
|---|
| Number | String | ToNumber(y) — String vira Number |
| String | Number | ToNumber(x) — String vira Number |
| BigInt | String | ToBigInt(y) — String vira BigInt |
| String | BigInt | ToBigInt(x) — String vira BigInt |
| Boolean | Qualquer | ToNumber(x) — Boolean vira Number (0 ou 1) |
| Qualquer | Boolean | ToNumber(y) — Boolean vira Number (0 ou 1) |
| Object | String/Number/BigInt/Symbol | ToPrimitive(x) — Object vira primitivo |
| String/Number/BigInt/Symbol | Object | ToPrimitive(y) — Object vira primitivo |
| BigInt | Number | Compara valores matemáticos diretamente |
| Number | BigInt | Compara valores matemáticos diretamente |
| null | undefined | true (caso especial) |
| undefined | null | true (caso especial) |
| null | Qualquer (exceto undefined) | false |
| undefined | Qualquer (exceto null) | false |
Galeria de Resultados Surpreendentes
Aqui estão comparações que surpreendem a maioria dos desenvolvedores:
String & Number
snippetJavaScript
// String convertida para Number1 == "1" // true ("1" → 1)0 == "" // true ("" → 0)0 == "0" // true ("0" → 0)100 == "1e2" // true ("1e2" → 100) // Mas string com string é comparação direta"" == "0" // false (ambas strings, valores diferentes) // Conversões NaNNaN == "NaN" // false (NaN ≠ qualquer coisa, inclusive a si)0 == "hello" // false ("hello" → NaN, 0 ≠ NaN)
Coerção Booleana
snippetJavaScript
// Booleans viram 0 ou 1 PRIMEIROtrue == 1 // true (true → 1)false == 0 // true (false → 0)true == "1" // true (true → 1, "1" → 1)false == "" // true (false → 0, "" → 0) // Por isso estes confundem:true == "true" // false! (true → 1, "true" → NaN)false == "false" // false! (false → 0, "false" → NaN) // E estes parecem errados:true == 2 // false (true → 1, 1 ≠ 2)true == "2" // false (true → 1, "2" → 2, 1 ≠ 2)
Armadilha comum: true == "true" é false! O boolean true vira 1, e a string "true" vira NaN. Como 1 ≠ NaN, o resultado é false.
null & undefined
snippetJavaScript
// A relação especialnull == undefined // true (regra especial!)undefined == null // true // Mas não igualam mais nadanull == 0 // falsenull == false // falsenull == "" // falseundefined == 0 // falseundefined == false // falseundefined == "" // false // Isso é útil de verdade!let value = null;if (value == null) { // Pega AMBOS null E undefined console.log("Valor é nullish");}
Este é o ÚNICO caso de uso legítimo para ==. Usar value == null verifica null e undefined numa única comparação.
Arrays & Objetos
snippetJavaScript
// Arrays convertem via ToPrimitive (geralmente toString)[] == false // true ([] → "" → 0, false → 0)[] == 0 // true ([] → "" → 0)[] == "" // true ([] → "")[1] == 1 // true ([1] → "1" → 1)[1] == "1" // true ([1] → "1")[1,2] == "1,2" // true ([1,2] → "1,2") // Gotcha do array vazio[] == ![] // true! (veja explicação abaixo) // Objetos com valueOf/toStringlet obj = { valueOf: () => 42 };obj == 42 // true (obj.valueOf() → 42)
Passo a Passo: [] == ![]
Este é um dos resultados mais surpreendentes do JavaScript. Um array vazio [] iguala ![]? Vamos decompor:
Avaliar ![]
Primeiro, o JavaScript avalia ![].
[] é truthy (todos os objetos são truthy)![] portanto é false- Agora temos:
[] == false
Boolean para Number
Um lado é Boolean, então converte para Number.
false → 0- Agora temos:
[] == 0
Objeto para Primitivo
Um lado é Object, converte para primitivo.
[] → "" (array vazio vira string vazia)- Agora temos:
"" == 0
String para Number
Um lado é String, converte para Number.
"" → 0- Agora temos:
0 == 0
Comparação Final
snippetJavaScript
0 == 0 // true!
Por isso [] == ![] retorna true. Com ===, seria false imediatamente (tipos diferentes).
O Único Caso Aceitável para ==
snippetJavaScript
function greet(name) { if (name == null) { return "Olá, estranho!"; } return `Olá, ${name}!`;} greet(null); // "Olá, estranho!"greet(undefined); // "Olá, estranho!"greet("Alice"); // "Olá, Alice!"greet(""); // "Olá, !" (string vazia NÃO é null)greet(0); // "Olá, 0!" (0 NÃO é null)
Muitos guias de estilo (incluindo Airbnb e StandardJS) fazem exceção para value == null porque é uma forma limpa de verificar valores "nullish". Você também pode usar o operador nullish coalescing (??) ou optional chaining (?.) do ES2020.