I spent 2 hours debugging a login form because I used == instead of ===. The user typed "0" but my code compared it to the number 0 and let them through.
What you'll learn: All 8 JavaScript comparison operators and when to use each one
Time needed: 20 minutes
Difficulty: Beginner (but saves advanced developers from bugs)
You'll never second-guess which operator to use again. Plus I'll show you the exact mistakes that cost me hours of debugging time.
Why I Built This Guide
I've been writing JavaScript for 8 years, and comparison operator bugs still catch me off guard.
My setup:
- Chrome DevTools for testing
- Node.js for server-side examples
- Real production code that broke
What didn't work:
- Memorizing operator tables without context
- Assuming
==was "good enough" for simple cases - Ignoring type coercion until it bit me
The 8 JavaScript Comparison Operators
The problem: JavaScript has 8 comparison operators and half of them do type conversion automatically.
My solution: Learn them in pairs with real examples that show exactly when each breaks.
Time this saves: Hours of debugging weird conditional logic
Equality Operators (The Tricky Ones)
Stop Using == (Loose Equality)
The problem: == converts types automatically and creates unpredictable results.
My solution: Use === everywhere except for null checks.
Time this saves: Eliminates 80% of comparison bugs
// This drove me crazy for 2 hours
const userInput = "0"; // From a form field
const adminLevel = 0; // From database
if (userInput == adminLevel) {
console.log("User is admin!"); // This runs! 😱
}
// What actually happened:
console.log("0" == 0); // true (string converted to number)
console.log("" == 0); // true (empty string becomes 0)
console.log(false == 0); // true (false becomes 0)
console.log(null == undefined); // true (special case)
What this does: JavaScript converts both sides to the same type before comparing.
Expected output: Way more true results than you expect
Personal tip: "I only use == for checking if (value == null) because it catches both null and undefined"
Use === (Strict Equality) by Default
The problem: You need to compare values without surprise type conversion.
My solution: === compares both value and type - no surprises.
// My fixed login code
const userInput = "0"; // From form
const adminLevel = 0; // From database
if (userInput === adminLevel) {
console.log("User is admin!"); // Doesn't run ✅
}
// Clear, predictable results:
console.log("0" === 0); // false (different types)
console.log("hello" === "hello"); // true (same type and value)
console.log(5 === 5); // true (same type and value)
console.log(true === true); // true (same type and value)
What this does: Compares both the value and the type - no conversion.
Expected output: Only true when both type and value match exactly
Personal tip: "Set up ESLint with the eqeqeq rule to catch == usage automatically"
The != vs !== Trap
// This bug cost me a production incident
const status = "0"; // API returned string "0" for inactive
if (status != 0) {
console.log("User is active");
} else {
console.log("User is inactive"); // This runs! Wrong! 😱
}
// Fix with strict inequality:
if (status !== 0) {
console.log("User is active"); // This runs ✅
} else {
console.log("User is inactive");
}
// The difference:
console.log("0" != 0); // false (converts types)
console.log("0" !== 0); // true (different types)
Personal tip: "Use !== everywhere. The only exception is value != null for null/undefined checks"
Relational Operators (Usually Safe)
Greater Than and Less Than (> <)
The problem: These work great with numbers but get weird with strings.
My solution: Convert to numbers explicitly when comparing numeric strings.
// Number comparisons work perfectly:
console.log(10 > 5); // true
console.log(3 < 7); // true
console.log(5 > 5); // false
// String comparisons use alphabetical order:
console.log("apple" < "banana"); // true (alphabetical)
console.log("10" > "9"); // false! Alphabetical, not numeric
console.log("10" > "2"); // false! Alphabetical comparison
// My fix for numeric strings:
console.log(Number("10") > Number("9")); // true ✅
console.log(parseInt("10") > parseInt("9")); // true ✅
What this does: Compares values, but strings use alphabetical order.
Expected output: Numbers work intuitively, strings compare alphabetically
Personal tip: "Always convert to numbers when comparing numeric strings - don't rely on automatic conversion"
Greater/Less Than or Equal (>= <=)
The problem: Combines comparison with equality, inheriting both behaviors.
// Works great with numbers:
console.log(5 >= 5); // true
console.log(10 <= 15); // true
console.log(7 >= 10); // false
// Watch out with mixed types:
console.log("5" >= 5); // true (string converted to number)
console.log("" >= 0); // true (empty string becomes 0)
// My safe approach:
const userScore = "85"; // From form input
const passingScore = 70; // From config
if (Number(userScore) >= passingScore) {
console.log("User passed!"); // Clear intent ✅
}
Personal tip: "Explicit conversion makes your intent clear and prevents weird edge cases"
Real-World Comparison Examples
Form Validation That Actually Works
// This form validation burned me once
function validateAge(ageInput) {
// Wrong way (my original buggy code):
if (ageInput == "") {
return "Age is required";
}
if (ageInput < 18) {
return "Must be 18 or older";
}
// Right way (after learning the hard way):
const age = Number(ageInput);
if (ageInput === "" || isNaN(age)) {
return "Please enter a valid age";
}
if (age < 18) {
return "Must be 18 or older";
}
return "Valid age";
}
// Test cases that broke my original code:
console.log(validateAge("")); // Now works correctly
console.log(validateAge("abc")); // Now catches invalid input
console.log(validateAge("17")); // Correctly rejects
console.log(validateAge("25")); // Correctly accepts
API Response Handling
// Handling API responses safely
function processUserStatus(user) {
// Dangerous (my old way):
if (user.isActive == true) {
// Fails if isActive is "true" string
}
// Safe (my current approach):
if (user.isActive === true) {
return "User is active";
}
// For null/undefined checks, == is actually useful:
if (user.lastLogin == null) { // Catches both null and undefined
return "User never logged in";
}
return "User status unclear";
}
// Test with realistic API data:
const users = [
{ isActive: true, lastLogin: new Date() },
{ isActive: "true", lastLogin: null }, // String from some APIs
{ isActive: false, lastLogin: undefined }, // Missing property
];
users.forEach((user, index) => {
console.log(`User ${index + 1}: ${processUserStatus(user)}`);
});
Common Comparison Mistakes I've Made
Mistake 1: Trusting Automatic Conversion
// This looked innocent but broke everything:
const discount = "10%";
const minDiscount = 5;
if (discount > minDiscount) {
console.log("Good discount!"); // Never runs
}
// Problem: "10%" can't convert to a number
console.log(Number("10%")); // NaN
console.log(NaN > 5); // false
// My fix:
const discountPercent = parseInt(discount);
if (!isNaN(discountPercent) && discountPercent > minDiscount) {
console.log("Good discount!"); // Now works ✅
}
Mistake 2: Comparing Objects
// This one got me in a React component:
const user1 = { name: "John", id: 123 };
const user2 = { name: "John", id: 123 };
console.log(user1 === user2); // false! Different objects in memory
// My solution for object comparison:
function compareUsers(user1, user2) {
return user1.id === user2.id; // Compare unique properties
}
// Or use JSON for simple objects (be careful with this):
console.log(JSON.stringify(user1) === JSON.stringify(user2)); // true
Mistake 3: Array Comparisons
// Another gotcha that confused me:
console.log([] === []); // false (different arrays)
console.log([1,2,3] === [1,2,3]); // false (different arrays)
// My array comparison function:
function arraysEqual(arr1, arr2) {
if (arr1.length !== arr2.length) return false;
for (let i = 0; i < arr1.length; i++) {
if (arr1[i] !== arr2[i]) return false;
}
return true;
}
console.log(arraysEqual([1,2,3], [1,2,3])); // true ✅
Quick Reference (Save This)
// Use these by default:
=== // Strict equality (checks type and value)
!== // Strict inequality
> // Greater than
< // Less than
>= // Greater than or equal
<= // Less than or equal
// Use these only in specific cases:
== // Only for: value == null (checks null AND undefined)
!= // Only for: value != null (checks null AND undefined)
What You Just Learned
You now know how to avoid the comparison operator bugs that trip up most JavaScript developers.
Key Takeaways (Save These)
- Use
===everywhere: Prevents 80% of comparison bugs by avoiding type conversion - Convert types explicitly:
Number(userInput) > thresholdis clearer thanuserInput > threshold - Only use
==for null checks:value == nullcatches bothnullandundefined
Tools I Actually Use
- Chrome DevTools: Test comparison operators in the console instantly
- ESLint with eqeqeq rule: Catches
==usage automatically - VS Code with JavaScript extensions: Highlights type mismatches