Operators
??), optional chaining (?.), and how operator precedence determines evaluation order.
Arithmetic Operators
Arithmetic operators perform mathematical calculations. JavaScript supports all the standard math operators plus the powerful exponentiation (**) operator introduced in ES2016.
| Operator | Name | Example | Result |
|---|---|---|---|
+ | Addition | 10 + 3 | 13 |
- | Subtraction | 10 - 3 | 7 |
* | Multiplication | 10 * 3 | 30 |
/ | Division | 10 / 3 | 3.333... |
% | Modulus (remainder) | 10 % 3 | 1 |
** | Exponentiation ES2016 | 10 ** 3 | 1000 |
++ | Increment | x++ or ++x | x + 1 |
-- | Decrement | x-- or --x | x - 1 |
let a = 10, b = 3; console.log(a + b); // 13 — Addition console.log(a - b); // 7 — Subtraction console.log(a * b); // 30 — Multiplication console.log(a / b); // 3.333... — Division console.log(a % b); // 1 — Modulus (remainder) console.log(a ** b); // 1000 — Exponentiation (ES2016) // Increment & Decrement let x = 5; console.log(x++); // 5 (post-increment: returns THEN increments) console.log(x); // 6 console.log(++x); // 7 (pre-increment: increments THEN returns) console.log(x--); // 7 (post-decrement) console.log(x); // 6 // Useful tricks with modulo console.log(10 % 2 === 0); // true — even number check console.log(7 % 2 === 1); // true — odd number check
% to check even/odd numbers, cycle through a fixed range of values (like wrapping around an array), implement clocks and timers, or test divisibility. Pattern: num % divisor === 0 means evenly divisible.Assignment Operators
Assignment operators combine a mathematical operation with assignment into a single shorthand. They make code shorter and more readable.
let score = 100; score += 10; // score = score + 10 → 110 score -= 5; // score = score - 5 → 105 score *= 2; // score = score * 2 → 210 score /= 3; // score = score / 3 → 70 score %= 8; // score = score % 8 → 6 score **= 2; // score = score ** 2 → 36 // String concatenation shorthand let msg = "Hello"; msg += " World"; // msg = "Hello World" // Logical assignment operators (ES2021) let a2 = null; a2 ??= "default"; // if null/undefined, assign "default" console.log(a2); // "default" let b2 = 0; b2 ||= 42; // if falsy, assign 42 console.log(b2); // 42 (0 is falsy) let c2 = 5; c2 &&= 10; // if truthy, assign 10 console.log(c2); // 10 (5 is truthy)
Comparison Operators
Comparison operators compare two values and return a boolean (true or false). The most important distinction in JavaScript is between loose equality (==) and strict equality (===).
let x = 5, y = 10; console.log(x == 5); // true — loose equality (type coercion!) console.log(x === 5); // true — strict equality (NO coercion) console.log(x != 10); // true — loose inequality console.log(x !== y); // true — strict inequality console.log(x > 3); // true — greater than console.log(x < y); // true — less than console.log(x >= 5); // true — greater than or equal console.log(x <= 4); // false — less than or equal // ⚠️ The danger of == (loose equality / type coercion) console.log(5 == "5"); // true (coerces string "5" to number 5!) console.log(5 === "5"); // false (different types — no coercion) console.log(0 == false); // true (coerces boolean to 0!) console.log(0 === false); // false (different types) console.log(null == undefined); // true (special JS rule) console.log(null === undefined); // false (different types)
== operator does type coercion — it converts values before comparing, which causes subtle, hard-to-find bugs. 0 == false is true. "" == false is true. null == undefined is true. These are classic JavaScript traps. Use === always — it checks both value AND type.Logical Operators
Logical operators combine boolean expressions. They also support short-circuit evaluation — a powerful pattern used everywhere in real JS code.
// && (AND) — true only if BOTH sides are true console.log(true && true); // true console.log(true && false); // false console.log(5 > 3 && 10 > 5); // true // || (OR) — true if AT LEAST ONE side is true console.log(false || true); // true console.log(false || false); // false console.log(5 > 10 || 5 > 3); // true // ! (NOT) — inverts a boolean console.log(!true); // false console.log(!false); // true console.log(!(5 > 3)); // false // SHORT-CIRCUIT EVALUATION — key JS pattern! // && returns the first FALSY value, or the last value console.log(0 && "hello"); // 0 (falsy — stops early) console.log(1 && "hello"); // "hello" (truthy — returns last) // || returns the first TRUTHY value, or the last value console.log(0 || "default"); // "default" (0 is falsy) console.log("user" || "guest"); // "user" (truthy — stops early) // Real-world: default value pattern with || const username = null; const displayName = username || "Guest"; // "Guest" console.log(displayName);
Ternary Operator
The ternary operator is a one-line if/else expression. Syntax: condition ? valueIfTrue : valueIfFalse. It's perfect for simple conditional assignments and JSX in React.
// Syntax: condition ? valueIfTrue : valueIfFalse const age = 20; const status = age >= 18 ? "Adult" : "Minor"; console.log(status); // "Adult" // Nested ternary — use sparingly, can get hard to read const score2 = 75; const grade = score2 >= 90 ? "A" : score2 >= 80 ? "B" : score2 >= 70 ? "C" : "F"; console.log(grade); // "C" // Real-world: UI state const isLoggedIn = true; const btnText = isLoggedIn ? "Logout" : "Login"; const welcome = `Hello, ${isLoggedIn ? "user" : "guest"}!`; console.log(btnText); // "Logout" console.log(welcome); // "Hello, user!"
if/else block for readability. Readable code is better than clever code.Nullish Coalescing Operator (??)
The ?? operator returns the right-hand side only when the left side is null or undefined. Unlike ||, it does NOT trigger for other falsy values like 0, "", or false.
// ?? vs || — the key difference const userScore = 0; console.log(userScore || 100); // 100 (WRONG! 0 is falsy) console.log(userScore ?? 100); // 0 (correct — 0 is not null/undefined) const username2 = null; console.log(username2 ?? "Anonymous"); // "Anonymous" — null triggers ?? const count = undefined; console.log(count ?? 0); // 0 — undefined triggers ?? // Real-world: handling API responses safely const apiData = { name: "Alice", score: 0 }; const name3 = apiData.name ?? "Unknown"; // "Alice" const score3 = apiData.score ?? -1; // 0 (not -1!) console.log(name3, score3); // "Alice" 0
0, empty string, or false are meaningful values in your data, use ??. If you want any falsy value to fall back to a default, use ||. This distinction matters a lot when working with scores, counts, or boolean flags from APIs.Optional Chaining (?.)
Optional chaining (?.) lets you safely access deeply nested object properties without throwing a TypeError when an intermediate value is null or undefined. It returns undefined instead of crashing.
const user = { name: "Alice", address: { city: "Karachi" } }; // Without optional chaining — CRASHES if address is null // console.log(user.profile.avatar); // TypeError: Cannot read properties of undefined! // With optional chaining — returns undefined safely console.log(user.address?.city); // "Karachi" console.log(user.profile?.avatar); // undefined (no error!) console.log(user.getName?.()); // undefined (method doesn't exist — no error!) // Combine ?. with ?? for clean fallbacks const city3 = user.address?.city ?? "Unknown city"; console.log(city3); // "Karachi" const avatar = user.profile?.avatar ?? "default-avatar.png"; console.log(avatar); // "default-avatar.png"
?. and ?? gives you safe access plus a clean fallback in one elegant expression: response?.user?.name ?? "Guest".Operator Precedence
Just like in math (PEMDAS/BODMAS), JavaScript operators have a precedence order — higher precedence operators execute first. When in doubt, use parentheses.
// Higher precedence executes first console.log(2 + 3 * 4); // 14 — * before + (like math!) console.log((2 + 3) * 4); // 20 — parentheses first // Precedence order (high → low, partial list): // 1. () — Parentheses (highest) // 2. ** — Exponentiation // 3. * / % — Multiplication, Division, Modulus // 4. + - — Addition, Subtraction // 5. > < >= <= — Comparison // 6. === !== == — Equality // 7. && — Logical AND // 8. || ?? — Logical OR, Nullish Coalescing // 9. ?: — Ternary // 10. = += -= — Assignment (lowest) // Real example — trace through step by step const result = 2 + 3 > 4 && 10 !== 5; // Step 1: 2 + 3 = 5 (+ before >) // Step 2: 5 > 4 = true (> before &&) // Step 3: 10 !== 5 = true (!== before &&) // Step 4: true && true = true console.log(result); // true // Tricky: exponentiation is right-associative console.log(2 ** 3 ** 2); // 512 — same as 2 ** (3 ** 2) = 2 ** 9 console.log((2 ** 3) ** 2); // 64 — use parens to force left-to-right
Summary
+ - * / % ** for math. Use % for even/odd checks and cycling. Pre/post ++-- behave differently.&& returns first falsy or last value. || returns first truthy or last value. These power default value patterns in real apps.?? when 0, "", or false are valid values. Use || for any-falsy defaults. Combine ?. and ?? for safe API data access.* before +, comparison before equality, && before ||. When unsure — use parentheses.% (modulo) operator do?5 == "5" in JavaScript??? (nullish coalescing) operator return?2 + 3 * 4 evaluate to in JavaScript?gradeCalc.js. Given a student's test scores (at least 5), write code that:1. Calculates the average score using arithmetic operators
2. Determines the letter grade using comparison and ternary: A (90+), B (80+), C (70+), D (60+), F (below 60)
3. Uses logical operators to check:
isHonorRoll (average >= 90 && attendance >= 90), isPassing (average >= 60)4. Uses
?? to handle missing attendance data (default to 100 if null)5. Logs a full report using template literals
💡 Show hints
- Sum all scores first, then divide by count for the average
- Use nested ternary for grade OR if/else (your choice for readability)
- Attendance might be null — use
const att = rawAttendance ?? 100 - isHonorRoll:
avg >= 90 && att >= 90 - Use a template literal for the final report card
// ── Grade Calculator ───────────────────────────── const scores = [85, 92, 78, 96, 88]; const rawAttendance = null; // simulating missing API data // 1. Calculate average using arithmetic operators const total = scores.reduce((sum, s) => sum + s, 0); const avg = total / scores.length; // 2. Letter grade using ternary operators const grade = avg >= 90 ? "A" : avg >= 80 ? "B" : avg >= 70 ? "C" : avg >= 60 ? "D" : "F"; // 4. Handle missing attendance with nullish coalescing const attendance = rawAttendance ?? 100; // null → 100% // 3. Logical operator checks const isPassing = avg >= 60; const isHonorRoll = avg >= 90 && attendance >= 90; // 5. Full report with template literals console.log(` ╔══════════════════════════╗ Student Report Card ───────────────────── Scores : ${scores.join(", ")} Average : ${avg.toFixed(1)}% Grade : ${grade} Attendance : ${attendance}% Passing : ${isPassing ? "✓ Yes" : "✗ No"} Honor Roll : ${isHonorRoll ? "✓ Yes" : "✗ Not yet"} ╚══════════════════════════╝`);