Operators and Expressions
TL;DR — Quick Summary
- Use
===and!==always —==causes type coercion bugs. - Short-circuit:
&&stops at the first falsy value;||stops at the first truthy value. - Use
??(nullish coalescing) for default values — it won't trigger on0or''like||does. - Use
?.(optional chaining) for safe nested property access — it returnsundefinedinstead of throwing.
Lesson Overview
Operators are the verbs of programming — they act on values (operands) to produce a result. Every calculation, every decision, every condition in your code uses operators. Understanding them deeply, including their precedence and edge cases, separates developers who write reliable code from those who constantly hunt mysterious bugs.
JavaScript has several operator categories: arithmetic (+ - * / % **), comparison (=== !== < >), logical (&& || ! ??), assignment (= += -=), and modern operators like optional chaining (?.) and nullish coalescing (??).
Conceptual Deep Dive
Arithmetic operators: Standard maths plus the modulo (%) which returns the remainder of division — useful for determining even/odd, cycling through indexes, and time calculations.
Comparison operators: Always return true or false. Critical rule: always use === and !==, never == or !=.
Logical operators and short-circuit evaluation:
&&(AND): returns the first falsy value, or the last value if all are truthy — stops early||(OR): returns the first truthy value, or the last value if all are falsy — stops early!(NOT): negates a boolean??(Nullish coalescing): returns right side only if left isnullorundefined— safer than||for default values
Optional chaining (?.): safely accesses nested properties without throwing if intermediate values are null/undefined.
Implementation Lab
// Arithmetic operators
const a = 10, b = 3;
console.log(a + b); // 13
console.log(a - b); // 7
console.log(a * b); // 30
console.log(a / b); // 3.333...
console.log(a % b); // 1 ← modulo: remainder of 10÷310÷3
console.log(2 ** 10); // 1024 ← exponentiation
// Modulo real-world uses
const hour = 14;
console.log(hour % 12 || 12); // 2 ← convert 24hr to 12hr
const isEven = n => n % 2 === 0;
console.log(isEven(4)); // true
console.log(isEven(7)); // false
// Assignment shorthand
let score = 100;
score += 25; // score = score + 25 → 125125
score -= 10; // 115
score *= 2; // 230
score /= 5; // 46
score **= 2; // 2116
// Increment / decrement
let count = 0;
count++; // 1 (post-increment: returns old value then increments)(post-increment: returns old value then increments)
++count; // 2 (pre-increment: increments then returns new value)(pre-increment: increments then returns new value)
count--; // 1// Short-circuit evaluation
// && returns first falsy OR last value
console.log(true && 'hello'); // 'hello' (both truthy, returns last)(both truthy, returns last)
console.log(false && 'hello'); // false (stops at first falsy)(stops at first falsy)
console.log(null && doSomething()); // null (doSomething never called)(doSomething never called)
// || returns first truthy OR last value
console.log('user' || 'guest'); // 'user'
console.log('' || 'guest'); // 'guest' ('' is falsy)('' is falsy)
console.log(0 || 42); // 42 (0 is falsy)(0 is falsy)
// ?? (nullish coalescing) — only triggers on null/undefined, NOT 0 or '') — only triggers on null/undefined, NOT 0 or ''
console.log(0 || 'default'); // 'default' (0 is falsy — often wrong!)(0 is falsy — often wrong!)
console.log(0 ?? 'default'); // 0 ← correct! 0 is a valid value0 is a valid value
console.log(null ?? 'default'); // 'default'
console.log(undefined ?? 'default'); // 'default'
// ?. (optional chaining) — safe property access) — safe property access
const user = { profile: { name: 'Alice' } };
const guest = null;
console.log(user?.profile?.name); // 'Alice'
console.log(guest?.profile?.name); // undefined (no error!)(no error!)
console.log(user?.address?.city); // undefined (no error!)(no error!)
// Practical: default values with ??
const getDisplayName = (user) => user?.name ?? 'Anonymous';
console.log(getDisplayName({ name: 'Bob' })); // 'Bob'
console.log(getDisplayName(null)); // 'Anonymous'const account = {
balance: 500,
isFrozen: false,
isVerified: true,
dailyWithdrawnAmount: 200
};
const DAILY_LIMIT = 1000;
const withdrawalAmount = 300;
// Complex condition using multiple operators
const hasEnoughBalance = account.balance >= withdrawalAmount;
const withinDailyLimit = (account.dailyWithdrawnAmount + withdrawalAmount) <= DAILY_LIMIT;
const isAccountActive = !account.isFrozen && account.isVerified;
const canWithdraw = hasEnoughBalance && withinDailyLimit && isAccountActive;
if (canWithdraw) {
const newBalance = account.balance - withdrawalAmount;
console.log(`✅ Withdrawal approved. New balance: $${newBalance}`New balance: $${newBalance}`);
} else {
const reason = !hasEnoughBalance ? 'Insufficient funds'
: !withinDailyLimit ? 'Daily limit exceeded'
: 'Account inactive';
console.log(`❌ Denied: ${reason}`{reason}`);
}Pro Tips — Senior Dev Insights
The ??= (nullish assignment) operator assigns only if the variable is null/undefined: user.name ??= 'Anonymous' — cleaner than a full if statement.
Chaining ?. with ?? is a powerful pattern: user?.settings?.theme ?? 'dark' safely reads a nested value with a fallback.
Prefer named intermediate variables for complex conditions — const canPurchase = isAdult && hasBalance && isVerified reads like English and is easier to debug.
Common Developer Pitfalls
|| for default values when 0 or empty string are valid — count || 10 replaces a valid 0. Use ?? instead: count ?? 10.2 + 3 * 4 is 14, not 20. Use parentheses in complex expressions.++count vs count++ — they behave differently when used in an expression. Pre-increment returns the new value; post-increment returns the old value.isLoggedIn && saveData() works but can be confusing. Prefer an explicit if statement for side effects.Interview Mastery
== (loose equality) performs type coercion before comparing — '5' == 5 is true because '5' is converted to 5. === (strict equality) checks both value and type with no coercion — '5' === 5 is false. Always use === to avoid subtle bugs. The only case for == is checking null/undefined simultaneously: value == null catches both null and undefined, which can be convenient.
&& (AND) evaluates left to right and stops (short-circuits) at the first falsy value, returning it. If all values are truthy, it returns the last one. Example: null && doWork() — doWork never runs. || (OR) stops at the first truthy value. Example: '' || 'default' returns 'default'. These are used for conditional execution: isLoggedIn && renderDashboard(), and default values: username || 'Guest'. However, use ?? for numeric/string defaults since 0 and '' are falsy but valid.
% returns the remainder after integer division: 10 % 3 = 1, 15 % 5 = 0. Real-world uses: even/odd detection (n % 2 === 0), cycling through items (index % array.length for circular navigation), time conversion (totalMinutes % 60 for remaining minutes), pagination (checking if a page number is a multiple), and alternating patterns (i % 2 for striped rows). It's one of the most useful operators for algorithmic problems.
Use ?? (nullish coalescing) when 0, false, or '' are valid values that should NOT be replaced by a default. || treats all falsy values as needing a default: 0 || 10 gives 10, which is wrong if 0 is a valid count. ?? only triggers when the left side is null or undefined: 0 ?? 10 gives 0. Rule of thumb: use ?? for 'value missing entirely', use || for 'value is falsy (logically empty)'.
Hands-on Lab Exercises
Build an order calculator: price, quantity, discount (%), and tax rate. Use arithmetic and assignment operators to compute the final total with each step logged.
Write a password strength checker using logical operators: check length >= 8, has uppercase, has number, has special char. Combine with && to give an overall strength score.
Experiment with short-circuit evaluation: use && to conditionally call a function, use || and ?? as default values — notice the difference when the value is 0.
Build an age-gating function that uses comparison and logical operators to check if a user can: vote (18+), rent a car (21+), get a senior discount (65+).
Real-World Practice Scenarios
(role === 'admin') || (role === 'superuser'). Grant read access if isLoggedIn && !isSuspended.score > 1000 && (noDeaths || timeBonusEarned). Use ?? for a default player name.?. to safely read response?.data?.user?.name ?? 'Unknown' without crashing on missing properties.Deepen Your Knowledge
Operators and Expressions
TL;DR — Quick Summary
- Use
===and!==always —==causes type coercion bugs. - Short-circuit:
&&stops at the first falsy value;||stops at the first truthy value. - Use
??(nullish coalescing) for default values — it won't trigger on0or''like||does. - Use
?.(optional chaining) for safe nested property access — it returnsundefinedinstead of throwing.
Overview
Operators are the verbs of programming — they act on values (operands) to produce a result. Every calculation, every decision, every condition in your code uses operators. Understanding them deeply, including their precedence and edge cases, separates developers who write reliable code from those who constantly hunt mysterious bugs.
JavaScript has several operator categories: arithmetic (+ - * / % **), comparison (=== !== < >), logical (&& || ! ??), assignment (= += -=), and modern operators like optional chaining (?.) and nullish coalescing (??).
Deep Dive Analysis
<p><strong>Arithmetic operators:</strong> Standard maths plus the modulo (<code>%</code>) which returns the remainder of division — useful for determining even/odd, cycling through indexes, and time calculations.</p><p><strong>Comparison operators:</strong> Always return <code>true</code> or <code>false</code>. Critical rule: always use <code>===</code> and <code>!==</code>, never <code>==</code> or <code>!=</code>.</p><p><strong>Logical operators and short-circuit evaluation:</strong></p><ul><li><code>&&</code> (AND): returns the first <em>falsy</em> value, or the last value if all are truthy — stops early</li><li><code>||</code> (OR): returns the first <em>truthy</em> value, or the last value if all are falsy — stops early</li><li><code>!</code> (NOT): negates a boolean</li><li><code>??</code> (Nullish coalescing): returns right side only if left is <code>null</code> or <code>undefined</code> — safer than <code>||</code> for default values</li></ul><p><strong>Optional chaining</strong> (<code>?.</code>): safely accesses nested properties without throwing if intermediate values are null/undefined.</p>
Implementation Reference
// Arithmetic operators
const a = 10, b = 3;
console.log(a + b); // 13
console.log(a - b); // 7
console.log(a * b); // 30
console.log(a / b); // 3.333...
console.log(a % b); // 1 ← modulo: remainder of 10÷3
console.log(2 ** 10); // 1024 ← exponentiation
// Modulo real-world uses
const hour = 14;
console.log(hour % 12 || 12); // 2 ← convert 24hr to 12hr
const isEven = n => n % 2 === 0;
console.log(isEven(4)); // true
console.log(isEven(7)); // false
// Assignment shorthand
let score = 100;
score += 25; // score = score + 25 → 125
score -= 10; // 115
score *= 2; // 230
score /= 5; // 46
score **= 2; // 2116
// Increment / decrement
let count = 0;
count++; // 1 (post-increment: returns old value then increments)
++count; // 2 (pre-increment: increments then returns new value)
count--; // 1// Short-circuit evaluation
// && returns first falsy OR last value
console.log(true && 'hello'); // 'hello' (both truthy, returns last)
console.log(false && 'hello'); // false (stops at first falsy)
console.log(null && doSomething()); // null (doSomething never called)
// || returns first truthy OR last value
console.log('user' || 'guest'); // 'user'
console.log('' || 'guest'); // 'guest' ('' is falsy)
console.log(0 || 42); // 42 (0 is falsy)
// ?? (nullish coalescing) — only triggers on null/undefined, NOT 0 or ''
console.log(0 || 'default'); // 'default' (0 is falsy — often wrong!)
console.log(0 ?? 'default'); // 0 ← correct! 0 is a valid value
console.log(null ?? 'default'); // 'default'
console.log(undefined ?? 'default'); // 'default'
// ?. (optional chaining) — safe property access
const user = { profile: { name: 'Alice' } };
const guest = null;
console.log(user?.profile?.name); // 'Alice'
console.log(guest?.profile?.name); // undefined (no error!)
console.log(user?.address?.city); // undefined (no error!)
// Practical: default values with ??
const getDisplayName = (user) => user?.name ?? 'Anonymous';
console.log(getDisplayName({ name: 'Bob' })); // 'Bob'
console.log(getDisplayName(null)); // 'Anonymous'const account = {
balance: 500,
isFrozen: false,
isVerified: true,
dailyWithdrawnAmount: 200
};
const DAILY_LIMIT = 1000;
const withdrawalAmount = 300;
// Complex condition using multiple operators
const hasEnoughBalance = account.balance >= withdrawalAmount;
const withinDailyLimit = (account.dailyWithdrawnAmount + withdrawalAmount) <= DAILY_LIMIT;
const isAccountActive = !account.isFrozen && account.isVerified;
const canWithdraw = hasEnoughBalance && withinDailyLimit && isAccountActive;
if (canWithdraw) {
const newBalance = account.balance - withdrawalAmount;
console.log(`✅ Withdrawal approved. New balance: $${newBalance}`);
} else {
const reason = !hasEnoughBalance ? 'Insufficient funds'
: !withinDailyLimit ? 'Daily limit exceeded'
: 'Account inactive';
console.log(`❌ Denied: ${reason}`);
}Common Pitfalls
- •Using <code>||</code> for default values when <code>0</code> or empty string are valid — <code>count || 10</code> replaces a valid <code>0</code>. Use <code>??</code> instead: <code>count ?? 10</code>.
- •Forgetting operator precedence — <code>2 + 3 * 4</code> is <code>14</code>, not <code>20</code>. Use parentheses in complex expressions.
- •Mutating with <code>++count</code> vs <code>count++</code> — they behave differently when used in an expression. Pre-increment returns the new value; post-increment returns the old value.
- •Relying on short-circuit for side effects without clarity — <code>isLoggedIn && saveData()</code> works but can be confusing. Prefer an explicit <code>if</code> statement for side effects.
Hands-on Practice
- ✓Build an order calculator: price, quantity, discount (%), and tax rate. Use arithmetic and assignment operators to compute the final total with each step logged.
- ✓Write a password strength checker using logical operators: check length >= 8, has uppercase, has number, has special char. Combine with && to give an overall strength score.
- ✓Experiment with short-circuit evaluation: use && to conditionally call a function, use || and ?? as default values — notice the difference when the value is 0.
- ✓Build an age-gating function that uses comparison and logical operators to check if a user can: vote (18+), rent a car (21+), get a senior discount (65+).
Expert Pro Tips
Interview Preparation
Q: What's the difference between == and === in JavaScript?
Master Answer:
== (loose equality) performs type coercion before comparing — '5' == 5 is true because '5' is converted to 5. === (strict equality) checks both value and type with no coercion — '5' === 5 is false. Always use === to avoid subtle bugs. The only case for == is checking null/undefined simultaneously: value == null catches both null and undefined, which can be convenient.
Q: Explain short-circuit evaluation with examples of && and ||.
Master Answer:
&& (AND) evaluates left to right and stops (short-circuits) at the first falsy value, returning it. If all values are truthy, it returns the last one. Example: null && doWork() — doWork never runs. || (OR) stops at the first truthy value. Example: '' || 'default' returns 'default'. These are used for conditional execution: isLoggedIn && renderDashboard(), and default values: username || 'Guest'. However, use ?? for numeric/string defaults since 0 and '' are falsy but valid.
Q: What does the modulo (%) operator do and when would you use it?
Master Answer:
% returns the remainder after integer division: 10 % 3 = 1, 15 % 5 = 0. Real-world uses: even/odd detection (n % 2 === 0), cycling through items (index % array.length for circular navigation), time conversion (totalMinutes % 60 for remaining minutes), pagination (checking if a page number is a multiple), and alternating patterns (i % 2 for striped rows). It's one of the most useful operators for algorithmic problems.
Q: When would you use ?? instead of ||?
Master Answer:
Use ?? (nullish coalescing) when 0, false, or '' are valid values that should NOT be replaced by a default. || treats all falsy values as needing a default: 0 || 10 gives 10, which is wrong if 0 is a valid count. ?? only triggers when the left side is null or undefined: 0 ?? 10 gives 0. Rule of thumb: use ?? for 'value missing entirely', use || for 'value is falsy (logically empty)'.
Simulated Scenarios
Extended Reading
MDN: Expressions and operators
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators
MDN: Operator precedence
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence
JavaScript.info: Operators
https://javascript.info/operators
© 2026 DevHub Engineering • All Proprietary Rights Reserved
Generated on March 7, 2026 • Ver: 4.0.2
Document Class: Master Education
Confidential Information • Licensed to User