Loose equality in JavaScript: why == surprises, and its one valid use

Loose equality converts values before comparing them, which produces baffling results. Here are its rules and its single recommended use.
3 min read
Believemy logo

Two equals signs instead of three, one character less, and a radically different behavior. This is the operator that earned JavaScript its reputation as an unpredictable language, and the reputation is deserved.


Definition

Loose equality compares two values after converting them to a common type. When both operands share a type, it behaves exactly like Strict equality (===). All the trouble comes from the cases where the types differ.

JAVASCRIPT
console.log("2" == 2);   // true: the string becomes a number
console.log(2 === 2);    // true, with no conversion

// The opposite is written !=
console.log("2" != 2);   // false

This automatic conversion has a name, Coercion (type conversion), and it follows precise rules that almost nobody remembers by heart. That is the whole problem: an operator whose answers require memorizing a table.


What the conversion actually produces

ComparisonResultWhy
"" == 0trueThe empty string becomes zero
"0" == 0trueThe string becomes the number zero
"" == "0"falseTwo strings, no conversion
[] == falsetrueBoth end up at zero
null == 0falsenull only compares with undefined

The first three rows are enough to demonstrate the problem: the operator is not transitive. The empty string equals zero, the string "0" equals zero, and yet the two strings are not equal to each other. No intuition survives that.

Good to know

The fourth row deserves a full look: an empty array is true inside an if, and yet it equals false with two equals signs. The two mechanisms are unrelated, the first converts to a boolean, the second to a number.


One exception draws a consensus, even among people who ban this operator everywhere else.

JAVASCRIPT
const value = null;

// Tests null AND undefined in a single go
if (value == null) {
  console.log("nothing to handle"); // prints
}

// The strict equivalent, longer
if (value === null || value === undefined) { }

Comparing against null also catches undefined, and nothing else: not zero, not the empty string, not false. It is the only place where two equals signs are safer than three, because they make it impossible to forget one of the two empty values.


Frequently asked questions

Question

Why does [] == ![] return true?

Because two conversions run one after the other. Negation first turns the array on the right into false, since an object is always true. That leaves an array and a boolean, both converted to numbers: zero on one side, zero on the other. So the comparison is true.


Question

Should the operator be banned in a project?

That is the default stance of linters, with a configurable exception for the comparison against null. The setting is a good compromise: it removes accidental conversions while keeping the short form that genuinely helps.


Question

How do I compare a form input with a number?

By converting explicitly rather than letting the operator do it. A form field always returns text: apply Number(input) or parseInt, check the result, then compare with Strict equality (===). The code gets longer and far more predictable.

Related terms

Discover our javaScript glossary

Every word of JavaScript explained simply: keywords, built-in objects, methods, errors and concepts. Clear definitions and examples that actually run, to learn and to troubleshoot.

Share this article

Want to help us? Share this article on your networks or even better: on your site, in an article or in your newsletter.