Comparisons
Compare JavaScript values safely with strict equality, string ordering, careful null checks, and the right way to detect NaN.
- 01Pick the safe equality checkUse
===to check if values are equal, and know when==changes a value first. - 02Predict which comes firstCompare strings, numbers, and a string with a number, and say the answer before you run it.
- 03Handle the special valuesCheck
null,undefined, andNaNwith the right tool for each.
A comparison asks a yes-or-no question
A comparison checks two values and answers true or false. These two answers are called booleans. Your code uses a comparison whenever it must make a choice. For example:
- Is the password long enough?
- Did the score reach 100?
- Is a value missing?
- Should this item come before that one?
You met these values in earlier lessons: Data types, Numbers & math, Strings, and Booleans, null & undefined. This lesson is about the operators that compare them. An operator is a symbol that does a job, like + or ===.
Use === to check if two values are equal. It asks: "Same type, and same value?" Use == only when you want it to change values before it compares. The common case is value == null, which is true for both null and undefined.
Picture a guard at the door of a club. A careful guard checks the name on your ID card. The guard also checks what kind of card it is. A relaxed guard lets you in if the name is close enough, even on the wrong kind of card. === is the careful guard. == is the relaxed one.
- In real life: The name on the ID card
- In JavaScript: The value:
5,"5",false,null - In real life: The kind of ID card
- In JavaScript: The type: number, string, boolean, and so on
- In real life: A careful guard checks both
- In JavaScript:
===checks the type and the value - In real life: A relaxed guard accepts a close match
- In JavaScript:
==may change a value first, so"0" == 0istrue
In this lesson you will:
- compare values in a live playground,
- step through how text is put in order,
- sort out
nullandundefined, - learn why
NaNis the one value that equality can't find.
Strict === and loose ==
INTERACTIVEJavaScript has two operators that check if two values are equal. The one you want most of the time is strict equality, written === (three equals signs). It gives true only when both sides have the same type and the same value.
const score = 5; console.log(score === 5);console.log("5" === score);console.log(false === 0);Line 1 stores the number 5 in score. Line 3 prints true: both sides are the number 5. Line 4 prints false: the left side is the text "5", and the right side is a number. Line 5 also prints false: false is a boolean, and 0 is a number.
Loose equality is written == (two equals signs). It may change one side into another type before it compares. This change is called conversion. You saw it in the Type conversion lesson. Here, remember one thing: == can make two different-looking values count as equal.
=== sees a string and a number, so it says false. == first changes the string "5" into the number 5, so it says true.const ageText = "18";const age = Number(ageText); console.log(age === 18);console.log(Number.isNaN(age));When a person types into a form on a web page, the browser gives you text, even if they typed a number. Line 1 holds that text, "18". Line 2 turns the text into a number once, with Number(). Line 4 prints true, because age is now the number 18.
Line 5 prints false. Number.isNaN() asks "is this NaN?" NaN is the value you get when turning something into a number fails. Here the change worked, so age is not NaN. NaN has its own section near the end.
const left = "0";const right = 0; console.log(left == right);console.log(left === right);console.log(Object.is(left, right));==true===falseObject.isfalse== turns the string into a number first. So text like "0" can equal the number 0.
==, ===, and Object.is().Try these pairs in the playground:
"0"and0""andfalsenullandundefined
The answers come from JavaScript itself. The third answer uses Object.is(), another way to check if two values are the same. You met it in Numbers & math. The later "Equality & sameness" lesson covers it in full.
The table below shows what == gives for seven common values. Find the left value in the first column. Then find the right value along the top. The cell where they meet is the answer to left == right.
| 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 type, use ===. If one of them came from a text box, turn it into a number yourself first: Number(input) === 5. Then anyone reading the code can see what happens. They don't need to remember all the rules of ==.
Objects must be the same object
REAL OUTPUTSNumbers, strings, booleans, null, and undefined are primitive values. They are simple, single values. For them, 3 === 3 just checks that the values match.
Objects and arrays work differently. For them, === asks: "Do both names point to the very same object?"
const firstCart = { total: 3 };const sameCart = firstCart;const otherCart = { total: 3 }; console.log(firstCart === sameCart);console.log(firstCart === otherCart);Line 1 makes a cart with a total of 3 and calls it firstCart. Line 2 does not make a new cart. It gives the same cart a second name, sameCart. So line 5 prints true.
Line 3 makes a second, separate cart. It also starts with a total of 3. But it is a different cart, so line 6 prints false.
firstCart and sameCart are two names for one cart, so firstCart === sameCart is true. otherCart is a second cart. It holds the same total, but it is not the same cart, so firstCart === otherCart is false.The table puts simple values and objects side by side. Each row is one comparison, its answer, and the reason.
| When you write | What you get | Why |
|---|---|---|
3 === 3 | true | Both sides are the number 3. |
"tea" === "tea" | true | Both sides are the same text. |
firstCart === sameCart | true | Both names point to one cart. |
firstCart === otherCart | false | These are two carts. Like two mugs that look the same: they are still two mugs. |
A reference is the link from a name to an object. When two names share one reference, they share one object. So a change made through one name shows up through the other name too. This matters when you pass a cart, a user, or a settings object to another part of an app.
const cart = { total: 3 };const savedCart = cart; cart.total = 4;console.log(savedCart.total);Line 2 makes savedCart point to the same object as cart. Line 4 changes that object's total to 4. Line 5 reads the total through the other name, savedCart, and prints 4. This is not a reason to avoid objects. It is a reason to know which one you need: the same object, or a new one.
Use === to ask whether two names point to the same object. To check whether two separate objects hold the same contents, compare the parts you care about. For example: firstCart.total === otherCart.total.
Comparing strings
STEP THROUGHFour more operators also give true or false:
<means "less than".>means "greater than".<=means "less than or equal to".>=means "greater than or equal to".
They are called relational operators, because they ask how two values relate: which one comes first? With two numbers, they work like in math class.
With two strings, JavaScript compares the text one character at a time, from the left. Every character has a number, called its character code. For example, "A" is 65 and "a" is 97. The character with the smaller code comes first.
console.log("tea" < "water");console.log("10" < "9");console.log(Number("10") < Number("9"));Line 1 prints true, because "t" comes before "w". Line 2 also prints true. Both sides are text, so JavaScript compares the first characters: "1" comes before "9". Line 3 turns both texts into numbers first. Then it asks the number question, "is 10 less than 9?", and prints false.
"1" and "9", are already different, and "1" comes first. So "10" < "9" is true. The "0" is never checked.Picture a dictionary that puts words in order by the number of each letter. You look at the first letter of two words. If they are the same, you move to the next letter. The first letter that is different decides which word comes first. In this dictionary, every word that starts with a capital letter comes before every word that starts with a small letter.
- In real life: Look at the first letter of each word
- In JavaScript: Compare the first character of each string
- In real life: If they match, look at the next letter
- In JavaScript: Compare the next character
- In real life: This dictionary puts capital letters first
- In JavaScript: Uppercase letters have smaller codes than lowercase letters
Step through the examples below. Pick one of three modes:
- Strings only: both sides are text.
"10" < "9"istrue, because"1"comes before"9". - Numbers only: both sides are numbers.
10 < 9isfalse. - String-number pairs: one side is text and one is a number. JavaScript turns the text into a number first, then compares.
Choose a mode and guess each answer. Then step through the real comparisons.
script
console.log("Apple" < "apple");console.log("10" < "9");console.log("a".charCodeAt(0));Look at "item10" and "item9". Text order puts "item10" first, because 1 comes before 9. A person would put item9 first. The later "Comparing & sorting text" lesson shows how to sort text the way people expect.
null & undefined comparisons
STEP THROUGHnull means "empty on purpose". undefined means "no value was given or found". They are two different values. But == has one special rule for them: null == undefined is true.
Here is the tricky part. == and the relational operators (<, >, <=, >=) follow different rules for these two values. You'll step through these three below, so watch them closely:
null == 0null >= 0undefined >= 0
function isMissing(value) { return value == null;} console.log(isMissing(null));console.log(isMissing(undefined));console.log(isMissing(""));This is the one place where == is used on purpose. The function isMissing gives back the answer from line 2. That line is true only for null or undefined. Lines 5 to 7 print true, true, and false. So an empty string, "", does not count as missing.
These lines look alike, but == and >= follow different rules. Go one step at a time.
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);Don't use <, >, <=, or >= on a value that might be missing. First check if it is missing: if (value == null) return;. Then compare it: value >= 0.
NaN never equals itself
STEP THROUGHNaN stands for "Not a Number". It is a special number value. You get it when a number calculation fails, like Number("tea"). The Numbers & math lesson showed Number.isNaN(). Here is why you need it: equality can't find NaN.
NaN: even NaN === NaN is false. Number.isNaN() asks the question you mean, "is this NaN?", and says true.You have two sealed boxes. Both are marked "unknown". Are the contents the same? You can't tell, so you can't say yes. JavaScript treats NaN the same way. It never says that NaN equals anything, not even another NaN.
- In real life: A sealed box marked unknown
- In JavaScript: A failed number result,
NaN - In real life: Two sealed boxes are never called the same
- In JavaScript:
NaN === NaNisfalse - In real life: A scanner made to spot those boxes
- In JavaScript:
Number.isNaN(value)
const failedPrice = Number("tea"); console.log(Number.isNaN(failedPrice));console.log(Number.isNaN("tea"));console.log(isNaN("tea"));Line 1 tries to turn "tea" into a number. That fails, so failedPrice is NaN. Line 3 prints true. Line 4 prints false: "tea" is text, not the value NaN.
Line 5 uses the older isNaN(), without Number. in front. It turns the text into a number first, gets NaN, and prints true. That answer is about the changed value, not about "tea". So use Number.isNaN() instead.
Equality can't find NaN. Step through to see which checks can.
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 last two lines use arrays, which have their own lesson later. For now, remember one habit: to ask "is this NaN?", write Number.isNaN(value).
Where you’ll use this
Comparisons appear wherever your program picks a path. In front-end code, values often start as text. Text can come from:
- form fields,
- parts of a web address (a URL),
- saved settings,
- data sent by a server.
Safe code turns that text into the right type where everyone can see it. Then it compares.
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");}Line 2 turns the text into a number. Line 4 checks if that failed, and asks for a number if so. Only then does line 6 compare the age with >=. Here the age is 18, so it prints Adult ticket.
Use this table when you are not sure which comparison to write. Find what you want to do in the first column. The next columns show what to write and why.
| When you want to | Write | Why |
|---|---|---|
| Check that two values are the same | a === b | It checks the type and the value, and changes nothing. |
| Compare text from a form with a number | Number(input) === expected | The change from text to number is easy to see and to test. |
Check if a value is null or undefined | value == null, or two === checks | This is the one == shortcut that many teams allow. |
| Check if a number calculation failed | Number.isNaN(value) | Equality can't find NaN. |
| Sort words the way people expect | Later: localeCompare or Intl.Collator | Plain < uses character codes, not the rules of a language. |
This is also why linters often warn about ==. A linter is a tool that checks your code for common mistakes. It doesn't mean == is useless. It means changes you can't see cause many bugs.
const savedCart = { total: 3 };const currentCart = { total: 3 }; console.log(savedCart === currentCart);console.log(savedCart.total === currentCart.total);These are two separate carts, so line 4 prints false. Their totals match, so line 5 prints true. In a real app, compare only the totals if matching totals is really the rule. An order number, the items, or the delivery address might matter too.
Common misconceptions
“== and === are basically the same.”
They only agree when no conversion happens. "0" == 0 is true, but "0" === 0 is false.
“= compares values.”
= stores a value. It puts the value on the right into the name on the left. To compare, use === or ==.
“String order is the same as dictionary order.”
Plain string comparison uses character codes. Uppercase letters come before lowercase letters. And "10" comes before "9".
“null >= 0 and null == 0 should match.”
They follow different rules. >= turns null into 0, so null >= 0 is true. == has its own rule for null: it only equals undefined. So null == 0 is false.
“Use x === NaN to find failed numbers.”
That comparison is always false. Use Number.isNaN(x).
score === 10Number(input) === 5Number.isNaN(total)value == nullinput == 5result === NaN
Put each piece of code in a group. Each card explains why it belongs there.
Practice: comparisons
6 EXERCISESTry each one before you open the hints. Every output was checked by running real JavaScript.
Predict the four 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. Line 1: == turns "0" into 0, so they match. Line 2: === sees a string and a number, so they don't match. Line 3: == has a special rule that matches null and undefined. Line 4: NaN never equals itself.
This code unlocks level 5, but entered is text. == quietly changes it into a number. Rewrite it: turn the text into a number yourself, then compare with ===.
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 changes the text where you can see it: Number(entered). After that, level === 5 compares two numbers, with no hidden change.
Predict the three outputs. This surprise is why a later lesson teaches other ways to sort text.
console.log("item10" < "item9");
console.log("10" < "9");
console.log(10 < 9);The outputs are true true false. As text, "item10" comes before "item9", and "10" comes before "9", because 1 comes before 9. As numbers, 10 is not less than 9.
Write the expression after return. It 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. It is false for 0, false, and an empty string. If your team doesn't allow == at all, write value === null || value === undefined.
Turning text into a number failed. What should you write to check 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") gives NaN. Number.isNaN(value) gives true. An equality check would give false.
A checkout page should show a message only when two carts have the same total. What should go inside the brackets of the if?
const savedCart = { total: 3 };
const currentCart = { total: 3 };
if (savedCart.total === currentCart.total) {
console.log("Same total");
}const savedCart = { total: 3 };
const currentCart = { total: 3 };
if (savedCart.total === currentCart.total) {
console.log("Same total");
}The carts are not the same object, so savedCart === currentCart is false. Both totals are 3, so savedCart.total === currentCart.total is true. Compare only the parts that your rule is about.
Quiz: check your understanding
8 QUESTIONSYour score counts first tries. Read every explanation. The wrong choices are common comparison bugs.
Question 1 of 8Which operator should you use to check if two values are equal?
Choose an answer to see the explanation.
Question 2 of 8What does this loose equality check print?
Read the code, then predictconsole.log("5" == 5);Choose an answer to see the explanation.
Question 3 of 8What does this text comparison print?
Read the code, then predictconsole.log("Apple" < "apple");Choose an answer to see the explanation.
Question 4 of 8What does
null >= 0print?Read the code, then predictconsole.log(null >= 0);Choose an answer to see the explanation.
Question 5 of 8What does
undefined >= 0print?Read the code, then predictconsole.log(undefined >= 0);Choose an answer to see the explanation.
Question 6 of 8Which expression correctly checks if a value is
NaN?Choose an answer to see the explanation.
Question 7 of 8What does
includesprint forNaN?Read the code, then predictconsole.log([NaN].includes(NaN));Choose an answer to see the explanation.
Question 8 of 8What does
===print for two carts made separately with the same total?Read the code, then predictconsole.log({ total: 3 } === { total: 3 });Choose an answer to see the explanation.
Key takeaways
- Use
===to check if two values are equal. It checks the type and the value. ==may change a value before it compares. Use it only on purpose, mostly asvalue == null.- For objects,
===asks if both names point to the same object. To check the contents, compare the parts you need. - Text is compared by character codes. So capital letters, and text like
"10", can surprise you. - Check if a value is missing before you use
<,>,<=, or>=. NaNnever equals itself. UseNumber.isNaN(value).
Remember the one-liner.
Compare with ===, turn values into the right type yourself, and use special checks for null and NaN.
Coming next: Logical operators.