Sabemos que existem dois comparadores de igualdade no Javascript:
== e ===, ou como são chamados: double equals e triple equals.Vamos dissecar aqui o funcionamento desses dois operadores e entender se um é melhor que o outro.
As mesmas regras explicadas são válidas para os comparadores de desigualdade
!= e !==.Triple Equals
Tecnicamente chamado de strict equality comparison (comparação de igualdade estrita) retorna
true caso os dois operandos sejam iguais. Esse operador usa o algoritmo de comparação de igualdade estrita. Entende-se por iguais aqueles que são do mesmo tipo e possuem o mesmo valor.- Se os operandos foram de tipos diferentes, retorna
1 === '1' // false
O primeiro operando tem o tipo Number, e o segundo, String
- Se ambos os operandos forem um objeto, retorna
trueapenas se eles se referem ao mesmo objeto
const first = { b: 'b' } const second = first first === second // true { a: 'a' } === { a: 'a' } // false
No segundo exemplo, apesar de ambos os objetos serem aparentemente iguais, eles foram criados em endereços de memória distintos, logo, do ponto de vista de igualdade estrita, são diferentes - ver Value Types and Reference Types
- Se ambos os operandos forem
nullouundefined, retornatrue
null === null // true undefined === undefined // true
- Se ambos os operandos forem
NaN, retornafalse
- Caso contrário, os valores dos operandos são comparados:
- Números devem ter o mesmo valor numérico.
+0e-0são considerados mesmo valor. - Strings devem ter os mesmos caracteres e na mesma ordem
- Booleans devem ser ambos
trueoufalse
Double Equals
Tecnicamente chamado de abstract equality comparison (comparação de igualdade abstrata), e também conhecido como loose equality, diferentemente do triple equals, esse comparador tenta converter operandos de diferentes tipos antes de efetuar a comparação.
Esse operador usa o algoritmo de comparação abstrata (ou ver ES6) que vamos detalhar abaixo.
Vamos considerar que estamos comparando
x e y, onde ambos podem ser de qualquer tipo.- Caso os operandos forem do mesmo tipo, o Javascript irá simplesmente usar o operador triple equals. Logo
2 == 2é o mesmo de2 === 2pois ambos são números (tipoNumber).
Porém, caso sejam de tipos diferentes, a regra para decidir qual operando converter depende dos tipos do operando.
- Se ambos os operandos forem
nullouundefined, retornatrue
- Se estivermos comparando uma
Stringcom umNumber, a string é convertida para número e então o operador é chamado novamente.
1 == '1' // 1 == ToNumber('1') // 1 == 1 // true
- Se estivermos comparando um
Booleancom qualquer outro tipo, o boolean é convertido para número e então o operador é chamado novamente
true == 1 // ToNumber(true) == 1 // 1 == 1 // true true == 2 // ToNumber(true) == 2 // 1 == 2 // false
O resultado do primeiro exemplo é
true pois a conversão de um Boolean true para número é sempre igual 1. Por outro lado false é igual a +0- Se um dos operandos for do tipo
String,NumberouSymbol, e o outro forObject, o objeto é convertido para primitivo e então o operador é chamado novamente
{ a: 'hello' } == '5' // ToPrimitive({ a: 'hello' }) == '5' // '[object Object]' == '5' // false [1,2,3] == '5' // ToPrimitive([1,2,3]) == '5' // '1,2,3' == '5' // false
Caso a comparação não se encaixe em nenhum cenário acima, retorna
falseObjects To Primitive
Ao converter objetos para primitivos, dois métodos podem ser usados:
valueOf e toString. Por padrão, o método valueOf do objeto é usado primeiro. Caso retorne um primitivo - ver Primitives - esse valor será usado. Uma segunda tentativa será realizada, dessa vez com o método
toString. Caso retorne um primitivo, esse valor será usado.Caso nenhum dos dois métodos retorne um valor primitivo, uma exceção será disparada.
const object = { a: 'hello' } object == '1' // ToPrimitive(object) == '1' // object.valueOf() // Retorna um objeto {} // object.toStirng() // retorna uma string '[object Object]' // '[object Object]' == '1' // false
const object = { a: 'hello' } object.toString = () => ({}) object == '1' // ToPrimitive(object) == '1' // object.valueOf() // Retorna um objeto {} // object.toStirng() // Retorna um objeto {} pois alteramos o método
O exemplo acima irá disparar uma exceção, pois nenhum dos dois métodos (
valueOf e toString) retornou um primitivo.Para objetos do tipo
Date, a ordem dos métodos é toString e valueOfConclusão
Com todas essas variáveis a se considerar, é melhor usarmos sempre o operador
===, pois não precisamos nos preocupar com tantas regras e observações, fora que seu uso torna a leitura e entendimento mais natural.