JavaScript developer Douglas Crockford has referred to JavaScript’s `==`

and `!=`

operators as evil twins that should be avoided. However, once you understand them, these operators aren’t that bad and can actually be useful. This article examines `==`

and `!=`

, explains how they work, and helps you get to know them better.

## The Problematic `==`

and `!=`

Operators

The JavaScript language incorporates two sets of equality operators: `===`

and `!==`

, and
`==`

and `!=`

. Understanding why there are two sets of equality operators and figuring out which ones to use in which situations has been a source of much confusion.
The `===`

and `!==`

operators aren’t difficult to understand. When both operands are of the same type and have the same value, `===`

returns `true`

, whereas `!==`

returns `false`

. However, when the values or types differ, `===`

returns `false`

and `!==`

returns `true`

.
The `==`

and `!=`

operators behave the same way when both operands have the same type. However, when the types differ, JavaScript *coerces*an operand to another type to make the operands compatible before comparing. The results are often confusing, as demonstrated below:

```
"this_is_true" == false // false
"this_is_true" == true // false
```

Because there are only two possible Boolean values, you might think that one of the expressions should evaluate to `true`

. However, they both evaluate to `false`

. Additional confusion occurs when you assume transitive relations (if a equals b and b equals c then a equals c) should apply:
```
'' == 0 // true
0 == '0' // true
'' == '0' // false
```

This example reveals that `==`

lacks transitivity. If the empty string equals the number 0, and if the number 0 equals the string consisting of the character 0, then the empty string should equal the string consisting of 0. But it doesn’t.
When faced with incompatible types while comparing operands via `==`

or `!=`

, JavaScript coerces one type to another to make them comparable. In contrast, it never performs type coercion (which leads to somewhat better performance) when using `===`

and `!==`

. Because of different types, `===`

always returns `false`

in the second example.
Understanding the rules that govern how JavaScript coerces an operand to a different type so that both operands are type-compatible before `==`

and `!=`

are applied can help you determine when it’s more appropriate to use `==`

and `!=`

, and to feel confident using these operators. In the next section, we’ll explore the coercion rules that are used with the `==`

and `!=`

operators.
## How Do `==`

and `!=`

Work?

The best way to learn how `==`

and `!=`

work is to study the ECMAScript Language Specification. This section focuses on ECMAScript 262. Section 11.9 of the spec addresses the equality operators.
The `==`

and `!=`

operators appear in grammar productions `EqualityExpression`

and `EqualityExpressionNoIn`

. (Unlike the first production, the second production avoids the `in`

operator.) Let’s examine the `EqualityExpression`

production, shown below.
```
EqualityExpression :
RelationalExpression
EqualityExpression == RelationalExpression
EqualityExpression != RelationalExpression
EqualityExpression === RelationalExpression
EqualityExpression !== RelationalExpression
```

According to this production, an equality expression is either a relational expression, an equality expression equal to a relational expression via `==`

, an equality expression not equal to a relational expression via `!=`

, and so on. (I ignore `===`

and `!==`

, which aren’t relevant to this article.)
Section 11.9.1 presents the following information on how `==`

works:
The production EqualityExpression :Section 11.9.2 presents similar information on howEqualityExpression==RelationalExpressionis evaluated as follows:

- Let
lrefbe the result of evaluatingEqualityExpression.- Let
lvalbe GetValue(lref).- Let
rrefbe the result of evaluatingRelationalExpression.- Let
rvalbe GetValue(rref).- Return the result of performing abstract equality comparison
rval==lval. (See 11.9.3.)

`!=`

works:
The production EqualityExpression :EqualityExpression!=RelationalExpressionis evaluated as follows:

- Let
lrefbe the result of evaluatingEqualityExpression.- Let
lvalbe GetValue(lref).- Let
rrefbe the result of evaluatingRelationalExpression.- Let
rvalbe GetValue(rref).- Let
rbe the result of performing abstract equality comparisonrval!=lval. (See 11.9.3.)- If
ristrue, returnfalse. Otherwise, returntrue.

`lref`

and `rref`

are references to the left and right sides of the `==`

and `!=`

operators. Each reference is passed to the `GetValue()`

internal function to return the corresponding value.
The heart of how `==`

and `!=`

work is specified by the Abstract Equality Comparison algorithm, which is presented in Section 11.9.3:
The comparisonStep 1 in this algorithm executes when the operand types are the same. It shows that`, where`

x==yand`x`

are values, produces`y`

trueorfalse. Such a comparison is performed as follows:

- If Type(
) is the same as Type(`x`

), then`y`

- If Type(
) is Undefined, return`x`

true.- If Type(
) is Null, return`x`

true.- If Type(
) is Number, then`x`

- If
is`x`

NaN, returnfalse.- If
is`y`

NaN, returnfalse.- If
xis the same Number value asy, returntrue.- If
xis+0andyis-0, returntrue.- If
xis-0andyis+0, returntrue.- Return
false.- If Type(
) is String, then return`x`

trueifand`x`

are exactly the same sequence of characters (same length and same characters in corresponding positions). Otherwise, return`y`

false.- If Type(
) is Boolean, return`x`

trueifand`x`

are both`y`

trueor bothfalse. Otherwise, returnfalse.- Return
trueifand`x`

refer to the same object. Otherwise, return`y`

false.- If
is`x`

nullandis`y`

undefined, returntrue.- If
is`x`

undefinedandis`y`

null, return true.- If Type(
) is Number and Type(`x`

) is String, return the result of the comparison`y`

== ToNumber(`x`

).`y`

- If Type(
) is String and Type(`x`

) is Number, return the result of the comparison ToNumber(`y`

) ==`x`

.`y`

- If Type(
) is Boolean, return the result of the comparison ToNumber(`x`

) ==`x`

.`y`

- If Type(
) is Boolean, return the result of the comparison`y`

== ToNumber(`x`

).`y`

- If Type(
) is either String or Number and Type(`x`

) is Object, return the result of the comparison`y`

== ToPrimitive(`x`

).`y`

- If Type(
) is Object and Type(`x`

) is either String or Number, return the result of the comparison ToPrimitive(`y`

) ==`x`

.`y`

- Return
false.

`undefined`

equals `undefined`

and `null`

equals `null`

. It also shows that nothing equals `NaN`

(Not a Number), two identical numeric values are equal, +0 equals -0, two strings with the same lengths and character sequences are equal, `true`

equals `true`

and `false`

equals `false`

, and two references to the same object are equal.
Steps 2 and 3 show why `null != undefined`

returns `false`

. JavaScript considers these values to be the same.
Beginning with Step 4, the algorithm becomes interesting. This step focuses on equality between Number and String values. When the first operand is a Number and the second operand is a String, the second operand is converted to a Number via the `ToNumber()`

internal function. The expression *== ToNumber(*

`x`

*) indicates recursion; the algorithm beginning in Section 11.9.1 is reapplied. Step 5 is equivalent to Step 4 but the first operand is of type String and must be converted to a Number type. Steps 6 and 7 convert a Boolean operand to Number type and recurse. If the other operand is Boolean, it will be converted to a Number on the next execution of this algorithm, which will recurse one more time. From a performance perspective, you might want to ensure that both operands are of Boolean type to avoid both recursion steps. Step 9 reveals that if either operand is of Object type, this operand is converted to a primitive value via the*

`y`

`ToPrimitive()`

internal function and the algorithm recurses.
Finally, the algorithm considers both operands unequal and returns `false`

in Step 10.
Although detailed, the Abstract Equality Comparison algorithm is fairly easy to follow. However, it refers to a pair of internal functions, `ToNumber()`

and `ToPrimitive()`

, whose inner workings need to be exposed to have a complete understanding of the algorithm.
The `ToNumber()`

function converts its argument to a Number, and is described in Section 9.3. The following list summarizes possible nonnumeric arguments and equivalent return values:
- If the argument is Undefined then return
**NaN**. - If the argument is Null then return
**+0**. - If the argument is Boolean true then return
**1**. If the argument is Boolean false then return**+0**. - If the argument has Number type then the input argument is returned — there is no conversion.
- If the argument has String type then Section 9.3.1 “ToNumber Applied to the String Type” applies. A numeric value corresponding to the string argument as indicated by the grammar is returned. If the argument doesn’t conform to the indicated grammar, NaN is returned. For example, argument
`"xyz"`

results in NaN being returned. Also, argument`"29"`

results in 29 being returned. - If the argument has Object type then apply the following steps:
- Let
*primValue*be ToPrimitive(*input argument*, hint Number). - Return ToNumber(
*primValue*).

- Let

`ToPrimitive()`

function takes an input argument and an optional PreferredType argument. The input argument is converted to a non-Object type. If an object is capable of converting to more than one primitive type, `ToPrimitive()`

uses the optional PreferredType hint to favor the preferred type. Conversion occurs as follows:
- If the input argument is Undefined then the input argument (Undefined) is returned — there is no conversion.
- If the input argument is Null then the input argument (Null) is returned — there is no conversion.
- If the input argument has Boolean type then the input argument is returned — there is no conversion.
- If the input argument has Number type then the input argument is returned — there is no conversion.
- If the input argument has String type then the input argument is returned — there is no conversion.
- If the input argument has Object type then a default value corresponding to the input argument is returned. The default value of an object is retrieved by calling the object’s
`[[DefaultValue]]`

internal method passing the optional PreferredType hint. The behaviour of`[[DefaultValue]]`

is defined for all native ECMAScript objects in Section 8.12.8.

`==`

and `!=`

and walking through the algorithm steps to evaluate them.
## Getting to Know the Evil Twins

Now that we know how`==`

and `!=`

work according to the ECMAScript specification, let’s put this knowledge to good use by exploring various expressions involving these operators. We’ll step through how these expressions are evaluated and discover why they are `true`

or `false`

.
For my first example, consider the following pair or expressions that were presented near the beginning of the article:
```
"this_is_true" == false // false
"this_is_true" == true // false
```

Follow these steps the evaluate these expressions according to the Abstract Equality Comparison algorithm:
- Skip Step 1 because the types are different:
`typeof "this_is_true"`

returns`"string"`

and`typeof false`

or`typeof true`

returns`"boolean"`

. - Skip steps 2 through 6, which don’t apply because they don’t match the operand types. However, Step 7 applies because the right argument is of type Boolean. The expressions are converted to
`"this_is_true" == ToNumber(false)`

and`"this_is_true" == ToNumber(true)`

. `ToNumber(false)`

returns +0 and`ToNumber(true)`

returns 1, which reduces the expressions to`"this_is_true" == +0`

and`"this_is_true" == 1`

, respectively. At this point the algorithm recurses.- Skip steps 1 through 4, which don’t apply. However, Step 5 applies because the left operand is of type String and the right operand is of type Number. The expressions are converted to
`ToNumber("this_is_true") == +0`

and`ToNumber("this_is_true") == 1`

. `ToNumber("this_is_true")`

returns NaN, which reduces the expressions to`NaN == +0`

and`NaN == 1`

, respectively. At this point, the algorithm recurses.- Step 1 is entered because each of NaN, +0, and 1 are of type Number. Steps 1.a and 1.b are skipped because they don’t apply. However, Step 1.c.i applies because the left operand is NaN. The algorithm now returns false (NaN isn’t equal to anything including itself) as the value of each original expression and rewinds the stack to fully exit the recursion.

`==`

, returning a value of `true`

:
```
var lifeAnswer = {
toString: function() {
return "42";
}
};
alert(lifeAnswer == 42);
```

The following steps show how JavaScript uses the Abstract Equality Comparison algorithm to arrive at true as the expression’s value:
- Skip steps 1 through 8, which don’t apply because they don’t match the operand types. However, Step 9 applies because the left operand is of type Object and the right operand is of type Number. The expression is converted to
`ToPrimitive(lifeAnswer) == 42`

. `ToPrimitive()`

calls`lifeAnswer`

‘s`[[DefaultValue]]`

internal method without a hint. According to Section 8.12.8 in the ECMAScript 262 specification,`[[DefaultValue]]`

calls the`toString()`

method, which returns`"42"`

. The expression is converted to`"42" == 42`

and the algorithm recurses.- Skip steps 1 through 4, which don’t apply because they don’t match the operand types. However, Step 5 applies because the left operand is of type String and the right operand is of type Number. The expression is converted to
`ToNumber("42") == 42`

. `ToNumber("42")`

returns 42, and the expression is converted to 42 == 42. The algorithm recurses and Step 1.c.iii executes. Because the numbers are the same,`true`

is returned and the recursion unwinds.

`true`

instead of `false`

:
```
'' == 0 // true
0 == '0' // true
'' == '0' // false
```

The following steps show how JavaScript uses the Abstract Equality Comparison algorithm to arrive at `true`

as the value of `'' == 0`

.
- Step 5 executes resulting in
`ToNumber('') == 0`

, which converts to`0 == 0`

and the algorithm recurses. (Section 9.3.1 in the specification states that*The MV [mathematical value] of StringNumericLiteral ::: [empty] is 0.*In other words, the numeric value of the empty string is 0.) - Step 1.c.iii executes, which compares 0 with 0 and returns
`true`

(and unwinds the recursion).

`true`

as the value of `0 == '0'`

:
- Step 4 executes resulting in
`0 == ToNumber('0')`

, which converts to`0 == 0`

and the algorithm recurses. - Step 1.c.iii executes, which compares 0 with 0 and returns
`true`

(and unwinds the recursion).

`true`

as the value of `'' == '0'`

. Because the two strings have different lengths (0 and 1), `false`

is returned.
## Conclusion

Perhaps you’re wondering why you should bother with`==`

and `!=`

. After all, previous examples have shown that these operators can be slower than their `===`

and `!==`

counterparts because of type coercions and recursion. You might want to use `==`

and `!=`

because there are contexts where `===`

and `!==`

offer no advantage. Consider the following example:
```
typeof lifeAnswer === "object"
typeof lifeAnswer == "object"
```

The `typeof`

operator returns a String value. Because a String value is being compared to another String value (`"object"`

), no type coercion takes place and `==`

is just as efficient as `===`

. Perhaps newcomers to JavaScript who’ve never encountered `===`

will find such code clearer. Similarly, the following code fragment requires no type coercion (both operands have Number type) and so `!=`

is no less efficient than `!==`

:
```
array.length !== 3
array.length != 3
```

These examples suggest that `==`

and `!=`

are appropriate in comparisons that require no coercions. When the operand types are different, `===`

and `!==`

are the way to go because they return `false`

rather than unexpected values (e.g., `false == ""`

returns `true`

). If the operand types are the same, there’s no reason not to use `==`

and `!=`

. Perhaps it’s time to stop fearing the evil twins, which aren’t so evil after you get to know them.
## Frequently Asked Questions (FAQs) about JavaScript Equality and Comparison Operators

### What is the difference between == and === in JavaScript?

In JavaScript, both == and === are comparison operators. However, they differ in how they compare values. The == operator, also known as the loose equality operator, performs type coercion before comparing. This means that if you compare two different types of values, JavaScript will try to convert one type to another before performing the comparison. On the other hand, the === operator, known as the strict equality operator, does not perform type coercion. It compares both the value and the type, which means that if two values are not the same type, JavaScript will consider them unequal.

### Why should I use === instead of == in JavaScript?

The use of === is generally recommended over == in JavaScript because it provides a stricter comparison, meaning it doesn’t perform type coercion and checks both value and type. This can help avoid unexpected results when comparing values of different types. For example, when using ==, JavaScript would consider the number 0 and the empty string “” as equal because it converts the types before comparison. However, with ===, these would be considered unequal because they are of different types.

### What is type coercion in JavaScript?

Type coercion in JavaScript refers to the automatic or implicit conversion of values from one data type to another. It happens when operators are used on values of different types, or when a certain type is expected. For example, when using the loose equality operator (==), JavaScript will try to convert the operands to a common type before making the comparison.

### How does JavaScript handle comparison of objects?

In JavaScript, objects are compared by reference, not by value. This means that even if two objects have the exact same properties and values, they are not considered equal because they refer to different objects in memory. The only case where objects are considered equal is when they refer to the exact same object.

### What is the difference between == and != in JavaScript?

The == and != are both comparison operators in JavaScript. The == operator checks if the values of two operands are equal or not, performing type coercion if necessary. On the other hand, the != operator checks if the values of two operands are not equal, also performing type coercion if necessary.

### What is the difference between === and !== in JavaScript?

The === and !== are both comparison operators in JavaScript. The === operator checks if the values of two operands are equal, considering both value and type. On the other hand, the !== operator checks if the values of two operands are not equal, considering both value and type.

### How can I compare two arrays in JavaScript?

In JavaScript, arrays are objects and are compared by reference, not by value. This means that even if two arrays contain the same elements in the same order, they are not considered equal because they refer to different objects in memory. To compare two arrays by their contents, you would need to compare each element individually.

### How does JavaScript handle comparison of null and undefined?

In JavaScript, null and undefined are considered loosely equal (==), because they both represent the absence of value. However, they are not strictly equal (===) because they are of different types.

### What is the order of precedence for comparison operators in JavaScript?

In JavaScript, comparison operators have the same precedence level. They are evaluated from left to right. However, it’s important to note that they have lower precedence than arithmetic and bitwise operators, but higher precedence than logical operators.

### Can I use comparison operators with strings in JavaScript?

Yes, you can use comparison operators with strings in JavaScript. When comparing strings, JavaScript uses lexicographic (dictionary) order. However, it’s important to note that uppercase letters are considered “smaller” than lowercase ones, because their ASCII values are smaller.

Jeff Friesen is a freelance tutor and software developer with an emphasis on Java and mobile technologies. In addition to writing Java and Android books for Apress, Jeff has written numerous articles on Java and other technologies for SitePoint, InformIT, JavaWorld, java.net, and DevSource.