Senior 7 min · March 05, 2026

JavaScript Operators: Null Coerced to 0 by == Causes Outage

Null userBalance with == 0 returns true, bypassing payment.

N
Naren · Founder
Plain-English first. Then code. Then the interview question.
About
 ● Production Incident 🔎 Debug Guide
Quick Answer
  • Operators are symbols that perform operations on values: arithmetic, assignment, comparison, logical, and more
  • Use === (strict equality) instead of == to avoid type coercion bugs
  • Compound assignment operators (+=, -=) update a variable in-place, cleaner than repeating the variable name
  • Nullish coalescing (??) only falls back for null/undefined, unlike || which catches all falsy values
  • The modulus (%) operator gives remainder — useful for even/odd checks and cyclic indexing
  • Optional chaining (?.) safely accesses nested properties without crashing on null or undefined
Plain-English First

Think of operators as the verbs of JavaScript — they're the action words that tell your code what to DO with values. Just like a calculator uses +, -, × and ÷ to work with numbers, JavaScript uses operators to add values, compare them, combine conditions, and make decisions. If variables are the boxes that hold your data, operators are the tools you use to work with what's inside those boxes.

Every single JavaScript program that has ever been written — from a simple age checker to a full e-commerce platform — relies on operators. They're the invisible machinery behind every calculation, every if/else decision, every loop condition, and every value assignment. Without operators, your code would just be a pile of data with nothing happening to it. They are, quite literally, how JavaScript thinks.

Before operators existed in programming languages, doing anything useful with data was painfully complex. Operators solve a fundamental problem: how do you tell a computer to compare two values, combine them, or use one to modify another? Operators give you a clean, readable shorthand for all of that. Instead of writing a paragraph of instructions to add two numbers, you just write a + b.

By the end of this article, you'll know every major category of JavaScript operator, understand exactly when and why to use each one, spot the classic mistakes that trip up beginners (and even some experienced devs), and be able to confidently answer operator-related questions in a JavaScript interview. Let's build this up piece by piece.

Arithmetic Operators — Making JavaScript Do the Math

Arithmetic operators are the most intuitive place to start because you already know them from school. They perform mathematical operations on numbers. JavaScript gives you the standard four — addition (+), subtraction (-), multiplication (), and division (/) — plus two more that often surprise beginners: modulus (%) and exponentiation (*).

The modulus operator is the one people forget exists. It gives you the remainder after division, not the result of division. So 10 % 3 gives you 1, because 3 goes into 10 three times with 1 left over. This is incredibly useful for things like figuring out if a number is odd or even, or cycling through items in a list.

Exponentiation () is the power operator. 2 8 means '2 to the power of 8', which is 256. You'll use this whenever you need to calculate areas, compound interest, or work with any kind of exponential growth.

JavaScript also has the ++ (increment) and -- (decrement) operators which add or subtract exactly 1 from a value. They look small but they're everywhere — especially inside loops.

Beware: JavaScript's floating-point arithmetic can produce unexpected results. 0.1 + 0.2 is 0.30000000000000004, not 0.3. This isn't a JavaScript bug — it's how IEEE 754 floating-point works in every language. For financial calculations, always use integers (cents) or a dedicated decimal library.

arithmeticOperators.jsJAVASCRIPT
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
// --- Arithmetic Operators in JavaScript ---

const applePrice = 1.50;      // price of one apple
const orangePrice = 2.00;     // price of one orange
const basketSize = 12;        // total items in basket
const appleCount = 5;         // number of apples bought

// + Addition: total cost of one apple and one orange
const combinedPrice = applePrice + orangePrice;
console.log('Combined price:', combinedPrice); // 3.5

// - Subtraction: how much more an orange costs than an apple
const priceDifference = orangePrice - applePrice;
console.log('Price difference:', priceDifference); // 0.5

// * Multiplication: total cost of 5 apples
const totalAppleCost = applePrice * appleCount;
console.log('Total apple cost:', totalAppleCost); // 7.5

// / Division: average price per item
const averagePrice = (applePrice + orangePrice) / 2;
console.log('Average price:', averagePrice); // 1.75

// % Modulus: how many apples are left over if we pack them into groups of 3
const applesLeftOver = appleCount % 3;
console.log('Leftover apples after packing in 3s:', applesLeftOver); // 2

// ** Exponentiation: a 3x3 storage crate holds this many items
const crateCapacity = 3 ** 2;
console.log('Crate capacity:', crateCapacity); // 9

// ++ Increment: one more apple added to the count
let currentAppleCount = appleCount; // let because we're about to change it
currentAppleCount++;
console.log('Apple count after adding one:', currentAppleCount); // 6

// -- Decrement: one apple removed
currentAppleCount--;
console.log('Apple count after removing one:', currentAppleCount); // 5
Output
Combined price: 3.5
Price difference: 0.5
Total apple cost: 7.5
Average price: 1.75
Leftover apples after packing in 3s: 2
Crate capacity: 9
Apple count after adding one: 6
Apple count after removing one: 5
Pro Tip: Use % to Check for Even/Odd Numbers
The single most common real-world use of % is checking if a number is even or odd. If (number % 2 === 0) it's even — because even numbers leave zero remainder when divided by 2. You'll use this pattern constantly in loops and UI logic.
Production Insight
Floating-point addition caused a currency calculation error that lost £0.01 per transaction.
Root cause: 0.1 + 0.2 !== 0.3 in IEEE 754.
Rule: never compare or sum floats for financial values — use BigInt or integer cents.
Key Takeaway
Modulus (%) gives remainder, not division result.
** is exponentiation.
Always handle floating-point precision with integers for money.

Assignment Operators — Storing and Updating Values Efficiently

You already know the basic assignment operator: =. It takes the value on the right and stores it in the variable on the left. But JavaScript has a whole family of compound assignment operators that combine assignment with arithmetic in one step, and they'll make your code much cleaner once you know them.

Compound assignment operators like +=, -=, *=, /=, and %= are shortcuts. Instead of writing score = score + 10, you write score += 10. It means exactly the same thing but it's shorter, less repetitive, and reads more naturally. Senior developers use these constantly.

Think of it like this: if you have a savings account with £200 in it and you deposit £50, you don't empty the account and refill it with £250. You just add £50 to what's already there. Compound assignment operators work the same way — they modify what's already in the variable rather than replacing it from scratch.

There's also the nullish assignment operator (??=) which only assigns a value if the variable is currently null or undefined. It's a newer addition but incredibly useful for setting default values safely.

A subtle danger: using assignment operators inside conditions (e.g., if (score = 10)) is a classic bug. The single = always assigns, not compares. Linters catch this — but they only work if you run them. Always prefer deliberate assignment before the condition.

assignmentOperators.jsJAVASCRIPT
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
// --- Assignment Operators in JavaScript ---

// Basic assignment: store the starting score
let playerScore = 0;
console.log('Starting score:', playerScore); // 0

// += Add and assign: player earns 10 points
playerScore += 10;
console.log('After earning 10 points:', playerScore); // 10

// += again: player earns a bonus 25 points
playerScore += 25;
console.log('After 25 point bonus:', playerScore); // 35

// -= Subtract and assign: player loses 5 points (penalty)
playerScore -= 5;
console.log('After 5 point penalty:', playerScore); // 30

// *= Multiply and assign: double score powerup activated!
playerScore *= 2;
console.log('After double score powerup:', playerScore); // 60

// /= Divide and assign: score halved due to wrong answer
playerScore /= 2;
console.log('After score halved:', playerScore); // 30

// %= Modulus and assign: only the remainder of score divided by 7 remains (a weird game rule!)
playerScore %= 7;
console.log('After modulus penalty:', playerScore); // 2  (30 divided by 7 = 4 remainder 2)

// **= Exponentiation and assign: score raised to the power of 3
playerScore **= 3;
console.log('After exponent powerup:', playerScore); // 8  (2 to the power of 3)

// ??= Nullish assignment: only sets a value if the variable is null or undefined
let playerName = null;
playerName ??= 'Guest Player'; // playerName is null, so this WILL assign
console.log('Player name:', playerName); // 'Guest Player'

let returningPlayer = 'Alex';
returningPlayer ??= 'Guest Player'; // returningPlayer has a value, so this will NOT assign
console.log('Returning player name:', returningPlayer); // 'Alex' — unchanged
Output
Starting score: 0
After earning 10 points: 10
After 25 point bonus: 35
After 5 point penalty: 30
After double score powerup: 60
After score halved: 30
After modulus penalty: 2
After exponent powerup: 8
Player name: Guest Player
Returning player name: Alex
Watch Out: = is Assignment, Not Equality
Using = inside an if condition (e.g. if (score = 10)) doesn't check if score equals 10 — it SETS score to 10, which always evaluates as true. Use == or === to compare values. This is one of the most common bugs beginners write and it won't throw an error, making it especially sneaky.
Production Insight
A developer used if (response = data) instead of if (response === data) in a middleware.
The condition always passed, and the code assigned data to response silently.
Rule: enable ESLint's no-cond-assign rule and never put assignment inside an if statement.
Key Takeaway
Compound assignment (+=, -=) reduces repetition.
??= sets only if null/undefined.
Never put = in a condition — use ===.

Comparison Operators — How JavaScript Makes Decisions

Comparison operators are the foundation of every decision your code makes. They compare two values and always return either true or false. This true/false result is what powers every if statement, every loop condition, and every ternary expression.

JavaScript has two equality operators and that trips everyone up: == (loose equality) and === (strict equality). The difference is huge. Loose equality (==) attempts to convert both values to the same type before comparing — so '5' == 5 is true because JavaScript quietly converts the string '5' into the number 5. Strict equality (===) compares both the value AND the type — so '5' === 5 is false because one is a string and one is a number.

For almost all situations, you should use === (strict equality). It does exactly what you think it does with no surprise type conversions happening behind the scenes. The == operator's type coercion behaviour is a notorious source of bugs.

The same logic applies to inequality: != (loose) vs !== (strict). Always prefer !== in your code.

Beyond equality, you have >, <, >=, <=. These work across strings too — JavaScript compares strings lexicographically by Unicode code point. That means '2' > '10' is true because '2' has a higher code point than '1'. Be careful comparing strings that represent numbers. Always convert to number first: Number('2') > Number('10').

comparisonOperators.jsJAVASCRIPT
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
// --- Comparison Operators in JavaScript ---
// Comparison operators always return true or false

const userAge = 20;
const minimumAge = 18;
const seniorAge = 65;
const inputAge = '20'; // this is a STRING, not a number — important!

// == Loose equality: compares values, NOT types (type coercion happens!)
console.log('Loose equality (number vs string):', userAge == inputAge); // true — JS converts '20' to 20

// === Strict equality: compares value AND type (no type coercion)
console.log('Strict equality (number vs string):', userAge === inputAge); // false — different types!
console.log('Strict equality (number vs number):', userAge === 20); // true — same value AND type

// != Loose inequality
console.log('Loose not-equal:', userAge != inputAge); // false — they ARE loosely equal

// !== Strict inequality (use this one!)
console.log('Strict not-equal:', userAge !== inputAge); // true — different types, so they are NOT strictly equal

// > Greater than
console.log('Is user old enough?', userAge > minimumAge); // true (20 > 18)

// < Less than
console.log('Is user under senior age?', userAge < seniorAge); // true (20 < 65)

// >= Greater than or equal to
console.log('Is user at least minimum age?', userAge >= minimumAge); // true (20 >= 18)

// <= Less than or equal to
console.log('Is user at or below senior age?', userAge <= seniorAge); // true (20 <= 65)

// Real-world usage: checking entry eligibility
if (userAge >= minimumAge) {
  console.log('Access granted — user meets the age requirement.');
} else {
  console.log('Access denied — user is too young.');
}
Output
Loose equality (number vs string): true
Strict equality (number vs string): false
Strict equality (number vs number): true
Loose not-equal: false
Strict not-equal: true
Is user old enough? true
Is user under senior age? true
Is user at or below senior age? true
Access granted — user meets the age requirement.
Interview Gold: Always Use === Instead of ==
Interviewers love to ask about == vs ===. The professional answer is: always use === (strict equality) unless you have a specific, deliberate reason to allow type coercion. Using == introduces unpredictable bugs because JavaScript's type coercion rules are complex and not always intuitive. Most style guides and linters enforce === by default.
Production Insight
String comparison in a sorting feature compared version strings like '2.10' and '2.9'.
'2.10' < '2.9' returned true because '1' < '9' lexicographically.
Rule: always parse numeric strings to numbers before comparison.
Key Takeaway
=== compares value and type; == coerces.
Always use ===.
String lexicographic comparison can surprise — convert to number.
Which equality operator should you use?
IfComparing two values that might be different types
UseUse === — it checks type and value, no coercion surprises.
IfComparing null and undefined specifically
UseUse == if you want them to be considered equal (they are loosely equal), but prefer explicit checks: x === null || x === undefined.
IfChecking if a number is 0 or false?
UseNever use == because 0 == false is true. Use === or convert to boolean explicitly.

Logical Operators — Combining Conditions Like a Pro

Logical operators let you combine multiple conditions into one expression. Instead of nesting a dozen if statements inside each other, you can chain conditions together cleanly on a single line. There are three core logical operators: && (AND), || (OR), and ! (NOT).

Think of && like a bouncer at a club with two rules: 'You must be over 18 AND have ID.' Both conditions must be true for you to get in. If either one fails, you're not getting through. That's &&.

The || operator is more lenient: 'You can enter if you have a VIP pass OR a regular ticket.' Just one condition needs to be true. That's ||.

The ! operator simply flips a boolean: !true is false and !false is true. It's useful for toggling states, like switching a dark mode setting on and off.

JavaScript also has two powerful modern operators: ?? (nullish coalescing) which returns the right side only if the left is null or undefined, and the optional chaining operator ?. which safely accesses properties without crashing when something is null. These two are modern essentials.

A critical nuance: && and || evaluate to one of their operands, not strictly to true or false. This is called short-circuit evaluation. For example, 0 && true evaluates to 0 (not false), and 'hello' || false evaluates to 'hello' (not true). This behavior is often used for conditional rendering or fallbacks — but it can trip you up when you expect a boolean.

logicalOperators.jsJAVASCRIPT
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
// --- Logical Operators in JavaScript ---

const hasValidTicket = true;
const hasVipPass = false;
const isAccountVerified = true;
const userAge = 17;
const minimumAge = 18;
let isDarkModeOn = false;

// && AND: BOTH conditions must be true
// Can user enter? They need a valid ticket AND must be old enough
const canEnterEvent = hasValidTicket && (userAge >= minimumAge);
console.log('Can enter event (ticket + age):', canEnterEvent); // false — age check fails

// What if the user WAS old enough?
const isOldEnough = true;
const canEnterIfOlderUser = hasValidTicket && isOldEnough;
console.log('Can older user enter with ticket:', canEnterIfOlderUser); // true — both pass

// || OR: at least ONE condition must be true
// Can user access premium content? They need EITHER a ticket OR a VIP pass
const canAccessPremium = hasValidTicket || hasVipPass;
console.log('Can access premium content:', canAccessPremium); // true — ticket alone is enough

// ! NOT: flips the boolean value
console.log('Is dark mode currently OFF?', !isDarkModeOn); // true — it's currently false, so !false = true

// Toggle dark mode using !
isDarkModeOn = !isDarkModeOn; // flip it from false to true
console.log('Dark mode after toggle:', isDarkModeOn); // true

// ?? Nullish Coalescing: use default only when value is null or undefined
const userDisplayName = null;
const displayName = userDisplayName ?? 'Anonymous User'; // null triggers the default
console.log('Display name:', displayName); // 'Anonymous User'

const savedUsername = 'techdev_99';
const safeDisplayName = savedUsername ?? 'Anonymous User'; // has a value, no default needed
console.log('Safe display name:', safeDisplayName); // 'techdev_99'

// ?. Optional chaining: safely access a property that might not exist
const userProfile = null;
// Without ?. this would CRASH with: TypeError: Cannot read properties of null
const profileCity = userProfile?.address?.city;
console.log('Profile city (safe access):', profileCity); // undefined — no crash!

// Combining && and || in a real check
const canPostComment = isAccountVerified && (hasValidTicket || hasVipPass);
console.log('Can post comment (verified + ticket/VIP):', canPostComment); // true
Output
Can enter event (ticket + age): false
Can older user enter with ticket: true
Can access premium content: true
Is dark mode currently OFF? true
Dark mode after toggle: true
Display name: Anonymous User
Safe display name: techdev_99
Profile city (safe access): undefined
Can post comment (verified + ticket/VIP): true
Pro Tip: Use ?? Instead of || for Default Values
Many developers use || for default values (e.g. name || 'Guest') but this has a bug: || treats 0, false, and empty string '' as falsy and will replace them with the default, even though they're valid values. The ?? operator only triggers for null and undefined, which is almost always what you actually want.
Production Insight
A form used || to default empty input to '0' — but when user entered 0 intentionally, it was overridden.
0 || '0' evaluates to '0' because 0 is falsy.
Rule: use ?? for defaults; use || only when you truly want to treat 0/false/'' as missing.
Key Takeaway
&& and || short-circuit and return an operand, not necessarily boolean.
?? only catches null/undefined.
?. prevents crashes on null access.

Ternary and Conditional Operators — Compact Decision Making

The ternary operator (? :) is a concise way to write an if-else statement on a single line. Its syntax is: condition ? exprIfTrue : exprIfFalse. It returns one of two values based on the truthiness of the condition.

It's not just a shorthand — it's an expression, meaning it can be used directly in assignments, return statements, or even inside other expressions. This makes it incredibly powerful for short conditional logic.

However, misuse is common. Nesting ternaries (ternary inside ternary) quickly becomes unreadable. A general rule: if the logic fits on one line and is obvious, use a ternary. If you start thinking 'else if', use a regular if-else or a switch statement instead.

The ternary operator is also a common source of bugs when developers forget that ? : returns a value and accidentally use assignment (=) inside one of the branches. Also, operator precedence can trip you up — wrap the ternary in parentheses if combined with other operators.

ternaryOperator.jsJAVASCRIPT
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// --- Ternary and Conditional Operators ---

const userAge = 17;
const minimumAge = 18;

// Ternary: condition ? ifTrue : ifFalse
const canAccess = userAge >= minimumAge ? 'Access granted' : 'Access denied';
console.log(canAccess); // 'Access denied'

// Using ternary in a return statement
function getGreeting(isMorning) {
  return isMorning ? 'Good morning' : 'Good evening';
}
console.log(getGreeting(true));  // 'Good morning'
console.log(getGreeting(false)); // 'Good evening'

// Nested ternary (use sparingly!)
const score = 85;
const grade = score >= 90 ? 'A' : score >= 80 ? 'B' : score >= 70 ? 'C' : 'D';
console.log('Grade:', grade); // 'B'

// Common pitfall: forgetting precedence — parentheses clarify
const x = 5, y = 10;
const result = (x > y) ? x : y; // result = 10 (max)
// Without parentheses around the condition, expression might be parsed incorrectly

// Avoid: assignment inside ternary
// const a = condition ? (b = 5) : (b = 10); // confusing, prefer if-else
Output
Access denied
Good morning
Good evening
Grade: B
Precedence Pitfall: Ternary Inside Expression
If you combine ternary with other operators like + or *, wrap the ternary in parentheses. Example: 'Price: ' + (isDiscounted ? 10 : 20) not 'Price: ' + isDiscounted ? 10 : 20 — the latter concatenates the string with the condition before the ternary evaluates.
Production Insight
A developer wrote return userId ? fetchUser(userId) : null without realizing ? has lower precedence than ? : in some contexts.
The code compiled but returned unexpected results when userId was 0 (falsy).
Rule: always use explicit parentheses around ternary conditions, especially when combined with other operators.
Key Takeaway
Ternary is an expression — use for simple if-else.
Avoid nesting ternaries; use if-else or switch for multiple branches.
Wrap ternary in parentheses when combining with other operators.

The Comma Operator and Other Odd Operators — Using the Less Common Ones

JavaScript has a few lesser-known operators that you won't use every day, but when you need them, they're indispensable. The comma operator (,) evaluates both operands and returns the second one. It's often used in for loops: for (let i = 0, j = 10; i < j; i++, j--). Outside loops, it can make code cryptic — use sparingly.

The delete operator removes a property from an object. It returns true if successful, false otherwise (it doesn't free memory directly). delete only works on object properties, not on variables or array elements (it leaves a hole).

The typeof operator returns a string indicating the type of an operand. Common traps: typeof null returns 'object' (a long-standing bug), and typeof array returns 'object' too. Use Array.isArray() to check arrays.

The instanceof operator checks whether an object is an instance of a specific constructor. It works across prototype chains, but fails across different execution contexts (e.g., iframes).

The grouping operator ( ) simply controls precedence in expressions. Use it liberally to make your intent clear.

oddOperators.jsJAVASCRIPT
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
// --- Odd Operators in JavaScript ---

// Comma operator: evaluates both, returns second
let a = (1, 2, 3);
console.log('a is:', a); // 3 (last value)

// Often used in for loops
for (let i = 0, j = 5; i < j; i++, j--) {
  console.log(i, j);
}
// Outputs: 0 5, 1 4, 2 3

// delete operator
const user = { name: 'Alice', age: 30 };
delete user.age;
console.log(user); // { name: 'Alice' }

// delete on array — leaves hole
const arr = [1, 2, 3];
delete arr[1];
console.log(arr); // [1, empty, 3] — length still 3

// typeof operator
console.log(typeof 'hello'); // 'string'
console.log(typeof 42);      // 'number'
console.log(typeof true);    // 'boolean'
console.log(typeof null);    // 'object' — known bug
console.log(typeof undefined); // 'undefined'
console.log(typeof []);      // 'object' — use Array.isArray()

// instanceof operator
const date = new Date();
console.log(date instanceof Date); // true
console.log(date instanceof Object); // true (Date extends Object)

// Grouping operator - clarify precedence
const result = (2 + 3) * 4; // 20, without parentheses would be 2 + 12 = 14
console.log(result); // 20
Output
a is: 3
0 5
1 4
2 3
{ name: 'Alice' }
[1, empty, 3]
string
number
boolean
object
undefined
object
true
true
20
Mental Model: typeof vs instanceof
  • typeof returns a primitive type string — works on any value.
  • instanceof checks the prototype chain — only works on objects.
  • typeof null === 'object' is a historical bug; check for null explicitly.
  • instanceof fails across realms (e.g., iframes, different Node contexts) — use Object.prototype.toString.call() for robustness.
Production Insight
A bug slipped through because typeof [] returned 'object', and the code assumed it was a plain object.
The bug: iterating over an array using for...in instead of for...of.
Rule: use Array.isArray() to distinguish arrays from plain objects.
Key Takeaway
Comma operator returns the last operand.
delete removes object properties, not array elements cleanly.
typeof null is 'object' — always check null separately.
Use Array.isArray() not typeof for array checks.
● Production incidentPOST-MORTEMseverity: high

Production Outage: Loose Equality Killed Our Billing Pipeline

Symptom
Users with a null account balance (first-time users with no transactions) were incorrectly marked as having paid $0, bypassing the payment gate.
Assumption
The developer assumed == would only match identical values, not knowing null and 0 are treated as loosely equal by JavaScript's type coercion rules.
Root cause
The condition if (userBalance == 0) was used to check if a user had a zero balance. When userBalance was null (no transactions yet), JavaScript coerced null to 0, making the condition true. The payment step was skipped for all new users.
Fix
Changed == to === and added an explicit null check: if (userBalance === 0 || userBalance === null) – but the real fix was to use === and handle null/undefined separately.
Key lesson
  • Always use === (strict equality) unless you have an explicit, documented reason for type coercion.
  • Linters (ESLint's eqeqeq rule) catch this automatically — enforce it in CI.
  • When dealing with numeric values that could be null or undefined, check for those explicitly before the equality comparison.
Production debug guideSymptom → Action grid for the most common operator pitfalls in production JavaScript.4 entries
Symptom · 01
Condition always evaluates to true even when you expect false
Fix
Check for accidental assignment: if (x = 10) assigns 10 to x, which is truthy. Use if (x === 10) and turn on ESLint's no-cond-assign rule.
Symptom · 02
Default value unexpectedly overwrites 0 or empty string
Fix
Check if you used || instead of ??. ?? only triggers for null/undefined, not for 0, '', or false. Switch to nullish coalescing if those are valid inputs.
Symptom · 03
Nested property access throws 'Cannot read properties of null'
Fix
Use optional chaining (?.) to safely access deeply nested properties. Replace obj.a.b with obj?.a?.b to return undefined instead of crashing.
Symptom · 04
Number comparison returns unexpected result for floating point values
Fix
Never use direct equality with floats. Use a tolerance: Math.abs(a - b) < 0.0001 instead of a === b. For currency, consider using integer cents or a library like decimal.js.
★ Quick Debug Cheat Sheet: Operator PitfallsOne-liner commands to diagnose common operator bugs in your codebase.
`==` used where `===` should be
Immediate action
Run ESLint with eqeqeq rule to flag all loose equality uses.
Commands
npx eslint --rule '{eqeqeq: ["error", "always"]}' src/
grep -rn '\b==[^=]' src/ --include='*.js'
Fix now
Replace every == with === except when you explicitly need type coercion (rare).
`||` default overwrites 0/false+
Immediate action
Identify all `||` fallback patterns in code review.
Commands
grep -rn '||' src/ --include='*.js' | grep -E '\|\s*['"\'"']'
Check if the left operand can legitimately be 0, false, or empty string.
Fix now
Replace value || defaultValue with value ?? defaultValue if 0/false/'' are valid.
Optional chaining not used — crashing on null+
Immediate action
Find all dot accesses in a file and decide if they need optional chaining.
Commands
grep -rn '\.' src/ --include='*.js' | grep -v '\?.' | head -50
Check if the accessed object can be null/undefined in any code path.
Fix now
Add ?. before property access when parent can be null: obj?.prop?.nested.
OperatorSymbolReturnsType Aware?Best Used For
Loose Equality==true / falseNo — coerces typesAlmost never — avoid it
Strict Equality===true / falseYes — exact matchAll equality checks
Loose Inequality!=true / falseNo — coerces typesAlmost never — avoid it
Strict Inequality!==true / falseYes — exact matchAll inequality checks
Logical AND&&true / false (or a value)N/ARequiring all conditions
Logical OR||true / false (or a value)N/AAccepting any condition
Nullish Coalescing??Left or right valueN/A — null/undefined onlySafe default values
Optional Chaining?.Value or undefinedN/ASafely accessing nested properties
Conditional (Ternary)? :Value based on conditionN/ACompact if-else assignment
Comma,Last operand valueN/AFor loop multiple increments
deletedeletetrue/falseN/ARemove object properties
typeoftypeofString type nameN/AType checking primitives
instanceofinstanceoftrue/falseN/A — checks prototype chainCheck object's class lineage

Key takeaways

1
Always use === (strict equality) instead of ==
it checks both value AND type, eliminating an entire class of type-coercion bugs that == quietly introduces.
2
The modulus operator % returns the remainder, not the result of division
it's your go-to tool for checking even/odd numbers and cycling through array indices.
3
Use ?? (nullish coalescing) instead of || for default values when 0, false, or empty string are valid inputs
|| treats all falsy values as missing, ?? only treats null and undefined as missing.
4
The optional chaining operator ?. lets you safely drill into nested object properties without crashing when a parent is null or undefined
it returns undefined instead of throwing a TypeError.
5
Ternary operator (?:) is an expression
use for simple if-else; avoid nesting. Always wrap ternary in parentheses when combined with other operators.
6
typeof null returns 'object'
always check for null explicitly. Use Array.isArray() to check for arrays, not typeof.

Common mistakes to avoid

5 patterns
×

Using = instead of === inside an if condition

Symptom
The condition always evaluates to true regardless of the actual value, because assignment (=) returns the assigned value, which is truthy unless it's 0, null, undefined, false, or empty string. The bug silently assigns the value instead of comparing.
Fix
Always use === for comparison conditions. Enable ESLint rule no-cond-assign (especially except-parens) to catch this. Example: if (userScore === 100) instead of if (userScore = 100).
×

Using == instead of === and getting surprised by type coercion

Symptom
Comparisons like userInput == 0 return true when userInput is '0' (string), false, null, or even an empty array — because == coerces types in complex ways. This leads to logic bugs that are difficult to trace.
Fix
Replace all == with === unless you have an explicit need for type coercion. Use linter rule eqeqeq with 'always' option. Example: if (userInput === 0) will only match number 0, not string '0' or null.
×

Using || for default values when 0 or false are valid inputs

Symptom
A user enters 0 (e.g., quantity = 0), but the code const quantity = input || 10 sets quantity to 10 because 0 is falsy. The bug is silent — data is overwritten without error.
Fix
Use nullish coalescing operator ?? instead: const quantity = input ?? 10. This only falls back to 10 when input is null or undefined, preserving 0, false, and empty string as valid values.
×

Confusing logical && and || with boolean return

Symptom
Expecting 0 || true to return false (because 0 is falsy), but it returns true (the second operand). Expecting true && 'hello' to return true, but it returns 'hello'. This can cause subtle bugs when using these operators in non-boolean contexts like JSX.
Fix
Recognize that && and || return one of the operands, not necessarily a boolean. When you need a boolean, use !! (double NOT) to coerce: !!(0 || true) returns true. Or better, explicitly write conditions that return booleans.
×

Forgetting that `typeof null === 'object'` is a bug

Symptom
Code like if (typeof value === 'object' && value !== null) is common, but many developers forget the null check. When value is null, the condition passes and later code crashes trying to access properties on null.
Fix
Always include explicit null check after typeof: if (value !== null && typeof value === 'object'). Or use value && typeof value === 'object' if null/falsy values should be excluded.
INTERVIEW PREP · PRACTICE MODE

Interview Questions on This Topic

Q01JUNIOR
What is the difference between == and === in JavaScript, and which one s...
Q02SENIOR
What does the nullish coalescing operator (??) do, and how is it differe...
Q03JUNIOR
What is the output of the following, and why: console.log(false == 0), c...
Q04SENIOR
Explain the difference between the spread operator (...) and the rest pa...
Q05SENIOR
How does the comma operator work? Give a real-world use case.
Q01 of 05JUNIOR

What is the difference between == and === in JavaScript, and which one should you use in production code and why?

ANSWER
== is loose equality — it performs type coercion before comparing, so '5' == 5 is true. === is strict equality — it compares both value and type without coercion, so '5' === 5 is false. In production, use === (or !==) almost always. The only acceptable use of == is when comparing null and undefined together: x == null is true for both null and undefined. But even then, many teams prefer explicit checks: x === null || x === undefined. Linters typically enforce === by default.
FAQ · 6 QUESTIONS

Frequently Asked Questions

01
What is the difference between == and === in JavaScript?
02
What does the % operator do in JavaScript?
03
When should I use ?? instead of || in JavaScript?
04
Why does typeof null return 'object'?
05
What is the comma operator and when would I use it?
06
What is the difference between spread and rest operator?
🔥

That's JS Basics. Mark it forged?

7 min read · try the examples if you haven't

Previous
Data Types in JavaScript
4 / 16 · JS Basics
Next
Functions in JavaScript