Comparisons
Compare JavaScript values safely with strict equality, string ordering, careful null checks, and the right way to detect NaN.
- 01Choose safe equalityUse
===by default and recognize what==converts. - 02Predict orderingCompare strings, numbers, and string-number pairs without guessing.
- 03Handle the weird edgesTreat
null,undefined, andNaNwith deliberate checks.
Comparison asks a yes-or-no question
A comparison is an expression that answers with a boolean: true or false. You use comparisons when code needs to make a choice: is the password long enough, did the score reach 100, is the value missing, or should this item come before that one?
You already met values in the Data types, Numbers & math, Strings, and Booleans, null & undefined lessons. This lesson focuses on the operators that compare those values.
Use === by default. It asks, “same type and same value?” Use == only when you deliberately want its conversions, especially the common value == null shortcut for null or undefined.
Imagine two guests at a club. The strict bouncer checks the ID photo and the kind of ID before letting someone in. The lenient bouncer is willing to translate nicknames and lookalikes first. That is the heart of === versus ==.
- In real life: Photo on the ID
- In JavaScript: The value itself: 5,
"5",false,null - In real life: Kind of ID card
- In JavaScript: The type: number, string, boolean, object-ish missing value
- In real life: Careful bouncer checks both
- In JavaScript:
===checks type and value - In real life: Lenient bouncer translates first
- In JavaScript:
==may convert, so"0" == 0is true
Where the analogy stops: A real bouncer uses judgment. JavaScript follows exact rules every time, even when those rules surprise you.
In this lesson you will compare values with a live equality matrix, step through string order, untangle null and undefined, and learn why NaN is the one value equality cannot find.
=== vs ==
INTERACTIVEJavaScript has several equality-looking operators. The one you want most of the time is strict equality, written ===. It returns true only when both sides have the same type and the same value.
5 === 5istrue: both are numbers, both are 5."5" === 5isfalse: string on the left, number on the right.false === 0isfalse: boolean on the left, number on the right.
Loose equality, written ==, may convert one side first. You learned the idea of implicit conversion in the Type conversion lesson. Here you only need the warning label: == can make different-looking values match.
const left = "0";const right = 0; console.log(left == right);console.log(left === right);console.log(Object.is(left, right));==true===falseObject.isfalseA string is converted to a number for ==, so text like "0" can match the number 0.
Object.is.Try "0" against 0, then "" against false, then null against undefined. Those are real results, not guesses. The third column uses Object.is, which you met in Numbers & math and will study deeply in “Equality & sameness.”
| left == right | 0 | "0" | "" | false | null | undefined | NaN |
|---|---|---|---|---|---|---|---|
| 0 | true | true | true | true | false | false | false |
| "0" | true | true | false | true | false | false | false |
| "" | true | false | true | true | false | false | false |
| false | true | true | true | true | false | false | false |
| null | false | false | false | false | true | true | false |
| undefined | false | false | false | false | true | true | false |
| NaN | false | false | false | false | false | false | false |
If two values should be the same kind of thing, use ===. If one came from a text input, convert it on purpose first: Number(input) === 5. Your future self can read that without remembering the full == algorithm.
Comparing strings
STEP THROUGHThe ordering operators <, >, <=, and >= also return booleans. With two numbers, they feel like math. With two strings, JavaScript compares text character by character using character codes.
Picture a dictionary that orders words by the number printed on each character. It is consistent, but it is not always how a person would alphabetize names.
- In real life: Look at the first letter
- In JavaScript: Compare the first character
- In real life: If tied, move to the next letter
- In JavaScript: Compare the next character
- In real life: This dictionary has a strange shelf order
- In JavaScript: Uppercase codes come before lowercase codes
Where the analogy stops: Human dictionaries consider language, accents, and locale. JavaScript's plain < does not. The future “Comparing & sorting text” lesson covers localeCompare and Intl.Collator.
Step through the examples. In string mode, "10" < "9" is true because JavaScript compares the first characters: "1" comes before "9". In number mode, 10 < 9 is false. In mixed mode, a string-number pair is converted to numbers before the relational comparison.
Choose a mode, predict each true or false, then step through the real comparisons.
script
console.log("Apple" < "apple");console.log("10" < "9");console.log("a".charCodeAt(0));Values like "item10" and "item9" show the same surprise: plain string order sees 1 before 9. Natural sorting and language-aware sorting belong to the later “Comparing & sorting text” lesson.
null & undefined comparisons
STEP THROUGHnull means “intentionally empty.” undefined means “no value was provided or found.” They are different values, but loose equality gives them one special handshake: null == undefined is true.
The tricky part is that equality and relational comparisons do not share one simple rule. Watch null == 0, null >= 0, and undefined >= 0 carefully.
These lines look similar, but equality and relational operators use different rules. Step slowly.
script
console.log(null === undefined);console.log(null == 0);console.log(null >= 0);console.log(null > 0);console.log(undefined == 0);console.log(undefined >= 0);Avoid comparing possibly missing values with <, >, <=, or >=. Check for missing first, then compare a real number: value != null && value >= 0 or an explicit if.
NaN never equals itself
STEP THROUGHNaN stands for “Not-a-Number,” a special number value that means a numeric operation failed. The Numbers & math lesson introduced Number.isNaN. Here is why it matters: equality cannot detect NaN.
If two boxes are both sealed and labeled “unknown,” you still do not know whether the contents match. JavaScript treats NaN that way for equality.
- In real life: A sealed box labeled invalid
- In JavaScript: A failed numeric result,
NaN - In real life: Comparing two mystery boxes
- In JavaScript:
NaN === NaNis still false - In real life: Use a scanner made for that label
- In JavaScript: Use
Number.isNaN(value)
Where the analogy stops: NaN is still a JavaScript number value, not an object or a real box. The analogy only explains why ordinary equality is the wrong tool.
Treat NaN like a mystery box: equality cannot identify it. Step through the safe checks.
script
console.log(NaN == NaN);console.log(Number.isNaN(NaN));console.log(Object.is(NaN, NaN));console.log([NaN].includes(NaN));console.log([NaN].indexOf(NaN));The array examples tease a future arrays lesson. For now, remember the professional habit: when the question is “is this NaN?”, ask Number.isNaN(value).
Where you’ll use this
Comparisons show up anywhere your program chooses a path. In front-end code, the values often start as text: form fields, URL pieces, stored settings, and data from a server. Safe code makes the conversion obvious before comparing.
const ageText = "18";const age = Number(ageText); if (Number.isNaN(age)) { console.log("Please enter a number.");} else if (age >= 18) { console.log("Adult ticket");} else { console.log("Child ticket");}| Situation | Prefer | Why |
|---|---|---|
| Same value, no surprises | a === b | Checks type and value without conversion. |
| Text input should be a number | Number(input) === expected | The conversion is visible and testable. |
| Missing means null or undefined | value == null or two strict checks | This is the one intentional loose shortcut many teams allow. |
| Detect invalid number | Number.isNaN(value) | Equality cannot find NaN. |
| Human text sorting | Later: localeCompare / Intl.Collator | Plain < uses character code order, not language rules. |
This is also why linters often warn about ==. They are not saying the operator is useless. They are saying hidden conversion is a common bug factory.
Common misconceptions
“== and === are basically the same.”
They agree only when conversion does not change the story. "0" == 0 is true; "0" === 0 is false.
“= compares values.”
= assigns. It stores the right-hand value in the left-hand name. Equality uses === or ==.
“String order is the same as dictionary order.”
Plain JavaScript string comparison uses character codes. Uppercase letters come before lowercase ones, and "10" comes before "9".
“null >= 0 and null == 0 should match.”
They use different rules. Relational comparison converts null to 0; loose equality has special cases and says null == 0 is false.
“Use x === NaN to find invalid numbers.”
That comparison is always false. Use Number.isNaN(x).
score === 10Number(input) === 5Number.isNaN(total)value == nullinput == 5result === NaN
Sort each comparison habit. Every card explains why it belongs there.
Practice: comparisons
5 EXERCISESTry each one before opening the hints. The exact outputs have been checked against real JavaScript.
Predict the four console outputs, in order.
console.log("0" == 0);
console.log("0" === 0);
console.log(null == undefined);
console.log(NaN === NaN);The outputs are true false true false: loose string-number equality matches, strict string-number equality does not, the nullish shortcut matches, and NaN never equals itself.
This code unlocks level 5 even though the input is text. Rewrite the idea so conversion is explicit and the comparison is strict.
const entered = "5";
if (entered == 5) {
console.log("Level 5 unlocked");
}const entered = "5";
const level = Number(entered);
if (level === 5) {
console.log("Level 5 unlocked");
}The fixed code names the conversion: Number(entered). After that, level === 5 is a strict number comparison instead of a hidden loose conversion.
Predict the three outputs. This is the surprise that leads to natural sorting later.
console.log("item10" < "item9");
console.log("10" < "9");
console.log(10 < 9);The outputs are true true false. String comparisons put "item10" before "item9" and "10" before "9"; number comparison says 10 is not less than 9.
Write the return expression for a function that should be true only for null or undefined.
function isMissing(value) {
return value == null;
}
console.log(isMissing(null));
console.log(isMissing(undefined));
console.log(isMissing(0));function isMissing(value) {
return value == null;
}
console.log(isMissing(null));
console.log(isMissing(undefined));
console.log(isMissing(0));value == null is true for null and undefined, and false for 0, false, and empty string. If your team bans all ==, use value === null || value === undefined.
A conversion failed. What expression should you use to detect that the result is NaN?
const value = Number("nope");
console.log(Number.isNaN(value));const value = Number("nope");
console.log(Number.isNaN(value));Number("nope") creates NaN. Number.isNaN(value) returns true; equality comparisons do not.
Quiz: check your understanding
7 QUESTIONSYour score counts first tries. Read every explanation; the wrong choices are designed to catch common comparison bugs.
Question 1 of 7Which comparison should be your default when checking whether two values are equal?
Choose an answer to see the explanation.
Question 2 of 7What does loose equality print here?
Read the code, then predictconsole.log("5" == 5);Choose an answer to see the explanation.
Question 3 of 7What does uppercase string order print?
Read the code, then predictconsole.log("Apple" < "apple");Choose an answer to see the explanation.
Question 4 of 7What does
null >= 0print?Read the code, then predictconsole.log(null >= 0);Choose an answer to see the explanation.
Question 5 of 7What does
undefined >= 0print?Read the code, then predictconsole.log(undefined >= 0);Choose an answer to see the explanation.
Question 6 of 7Which expression correctly detects the value
NaN?Choose an answer to see the explanation.
Question 7 of 7What does
includesprint forNaN?Read the code, then predictconsole.log([NaN].includes(NaN));Choose an answer to see the explanation.
Key takeaways
===is your default equality operator because it checks type and value.==converts before comparing; use it only deliberately, especially forvalue == null.- String ordering uses character codes, so capitals and number-looking strings can surprise you.
- Check possibly missing values before using relational operators like
>=. NaNnever equals itself; useNumber.isNaN(value).
Remember the one-liner.
Compare strictly by default, convert explicitly when needed, and use special tools for special values like null and NaN.
Up next: Logical operators.