Comparisons

You already know most of these from a maths class. Is one number bigger than another? Are two values the same? JavaScript answers those questions with operators that look familiar, plus a few that will surprise you.

Here’s the full set:

  • Greater than / less than: a > b, a < b.
  • Greater than or equal / less than or equal: a >= b, a <= b.
  • Equal: a == b. Watch the doubled sign. == asks a question (“are these equal?”), while a single a = b assigns a value. Mixing them up is one of the most common beginner bugs.
  • Not equal: maths writes , JavaScript writes a != b.

Most of this behaves the way your intuition expects. The interesting parts are the edges: comparing strings, comparing values of different types, and the strange things that null and undefined do. By the end you’ll have a short rule that sidesteps nearly all of the weirdness.

Every comparison gives back a boolean

Run any comparison and you get one of exactly two values:

  • true — the statement holds.
  • false — it doesn’t.

Nothing else. There’s no “maybe.”

alert( 2 > 1 );  // true
alert( 2 == 1 ); // false
alert( 2 != 1 ); // true

Because the result is an ordinary value, you can store it, pass it around, or print it like any other:

let result = 5 > 4; // the comparison runs first, then the result is stored
alert( result );    // true
5 > 4
evaluates to
true
stored in
result
A comparison is an expression that evaluates to a boolean, which you can then assign.

Comparing strings

Strings don’t have a numeric size, so JavaScript compares them the way a dictionary orders words: character by character, from the start. This is called lexicographical order.

alert( 'M' > 'D' );       // true
alert( 'Snow' > 'Snap' ); // true
alert( 'Star' > 'Sta' );  // true

The algorithm is short:

  1. Compare the first character of each string.
  2. If they differ, whichever character is “greater” decides the whole comparison. Done.
  3. If they’re equal, move to the second character and repeat.
  4. Keep going until one string runs out of characters.
  5. If both end together, the strings are equal. If one ran out first, the shorter one is “less.”

Walk through the three examples. 'M' > 'D' is settled on step one — M sits after D. 'Snow' versus 'Snap' takes longer:

S = S → tie
n = n → tie
o > a → ‘Snow’ wins
w · · never reached
'Snow' vs 'Snap' — the first difference decides everything.

And 'Star' > 'Sta': the first three characters match, then the first string still has an r while the second has nothing left. The longer string wins, so 'Star' is greater.

Type two strings and watch the comparison walk character by character until it finds the first difference — exactly the algorithm above.

interactiveLexicographical string comparison, step by step

Comparing different types

Give >, <, >=, <=, or == two operands of different types and JavaScript doesn’t refuse. It first converts the values to numbers, then compares those.

alert( '3' > 2 );   // true  — the string '3' becomes the number 3
alert( '05' == 5 ); // true  — '05' becomes 5

Booleans convert too: true turns into 1 and false into 0.

alert( true == 1 );  // true
alert( false == 0 ); // true
‘3’
→ Number →
3
>
2
true
true
→ Number →
1
==
1
true
Loose comparison of mixed types: everything is pulled to a number first.

Strict equality

Regular == has a blind spot: after converting to numbers, it can’t tell 0 apart from false.

alert( 0 == false ); // true

The empty string has the same problem, because it also converts to zero:

alert( '' == false ); // true

That’s the type conversion at work — both false and '' collapse to 0, so they match. Often you don’t want that. You want 0 (a real number) to stay distinct from false (a boolean) and from '' (an empty string).

The strict equality operator === compares without any type conversion.

If a and b are different types, a === b returns false on the spot — no attempt to convert, no coercion.

alert( 0 === false ); // false — number vs boolean, different types

There’s a matching strict non-equality operator !==, the strict version of !=.

0 == false
false → 0
0 === 0
result: true
0 === false
number ≠ boolean
stop, no conversion
result: false
== converts before comparing; === checks the type first and bails if they differ.

Yes, === is one character longer. But it says exactly what it means and removes a whole category of surprises. A good default: reach for === and !==, and only drop to == when you deliberately want the loose behavior.

Pick any two values and see both operators side by side. Notice how often == says true where === says false — that gap is the type conversion happening quietly behind ==.

interactive== versus ===

Comparing with null and undefined

Here’s where intuition breaks down. null and undefined follow special rules, and they differ depending on which operator you use.

=== strict
no conversion → each is its own type → null === undefined is false
== loose
special case → null == undefined is true, and neither equals anything else
< > <= >=
convert to number → null becomes 0, undefined becomes NaN
null and undefined behave differently under ===, ==, and the ordering operators.

Broken out:

Strict equality ===. No conversion happens, and null and undefined are distinct types, so they’re not equal:

alert( null === undefined ); // false

Loose equality ==. A dedicated rule makes them a matched pair: null and undefined equal each other and nothing else. Not 0, not false, not ''.

alert( null == undefined ); // true

Ordering < > <= >=. These convert to numbers. null becomes 0; undefined becomes NaN (Not-a-Number), which loses every comparison it’s part of.

These rules interact in ways that trip people up. Two examples show the traps, and then a rule to stay clear of them.

The null vs 0 puzzle

alert( null > 0 );  // (1) false
alert( null == 0 ); // (2) false
alert( null >= 0 ); // (3) true

Read those three together and it looks impossible. Line 3 says null is greater-than-or-equal to 0, yet line 1 says it isn’t greater, and line 2 says it isn’t equal either. If it’s neither greater nor equal, how can it be “greater or equal”?

The answer: lines 1 and 3 don’t play by the same rules as line 2.

  • > and >= are ordering operators, so they convert null to the number 0. Then 0 > 0 is false (line 1) but 0 >= 0 is true (line 3).
  • == uses the special couple rule instead. It never converts null to a number, and null only matches null or undefined — not 0. So line 2 is false.
null > 0→ convert →0 > 0false
null == 0→ couple rule, no convert →false
null >= 0→ convert →0 >= 0true
Line 2 takes a different code path than lines 1 and 3, which is why the results look contradictory.

undefined can’t be compared

undefined is even more antisocial. It loses every comparison:

alert( undefined > 0 );  // (1) false
alert( undefined < 0 );  // (2) false
alert( undefined == 0 ); // (3) false

Not greater, not less, not equal. Why does it hate zero this much?

  • Lines 1 and 2 convert undefined to NaN. And NaN is a special numeric value that returns false against everything, in every direction — even NaN < 0 and NaN > 0 are both false.
  • Line 3 uses the couple rule. undefined only equals null and itself, so comparing it to 0 gives false.

How to avoid the whole mess

You don’t need to memorize these edge cases. They’ll sink in with time, but there’s a reliable habit that keeps you out of trouble:

  • Treat any comparison involving null or undefined as suspect — except a strict === null or === undefined, which is safe and clear.
  • Never use >, <, >=, or <= on a variable that might be null or undefined, unless you’ve thought it through carefully. If a variable could hold those values, check for them on their own line first.

Run the naive check against the guarded one. The null and undefined cases are where they disagree — and where the naive version quietly does the wrong thing.

interactiveGuarding a comparison against null and undefined

Summary

  • Every comparison operator returns a boolean, true or false.
  • Strings compare lexicographically — character by character, using Unicode order, so case matters.
  • When the operands are different types, they convert to numbers first. The exception is strict equality ===, which never converts.
  • null and undefined equal each other and themselves under ==, but match no other value. Under === they’re distinct. Under ordering operators they convert to 0 and NaN.
  • Prefer === and !== so type conversion never surprises you.
  • Be wary of >, <, >=, <= on any variable that could be null or undefined. Check for those cases separately.