JavaScript Operators Explained — Types, Examples and Gotchas
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.
// --- 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
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
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.
// --- 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
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
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.
// --- 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.'); }
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 least minimum age? true
Is user at or below senior age? true
Access granted — user meets the age requirement.
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.
// --- 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
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
| Operator | Symbol | Returns | Type Aware? | Best Used For |
|---|---|---|---|---|
| Loose Equality | == | true / false | No — coerces types | Almost never — avoid it |
| Strict Equality | === | true / false | Yes — exact match | All equality checks |
| Loose Inequality | != | true / false | No — coerces types | Almost never — avoid it |
| Strict Inequality | !== | true / false | Yes — exact match | All inequality checks |
| Logical AND | && | true / false (or a value) | N/A | Requiring all conditions |
| Logical OR | || | true / false (or a value) | N/A | Accepting any condition |
| Nullish Coalescing | ?? | Left or right value | N/A — null/undefined only | Safe default values |
| Optional Chaining | ?. | Value or undefined | N/A | Safely accessing nested properties |
🎯 Key Takeaways
- Always use === (strict equality) instead of == — it checks both value AND type, eliminating an entire class of type-coercion bugs that == quietly introduces.
- 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.
- 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.
- 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.
⚠ Common Mistakes to Avoid
- ✕Mistake 1: Using = instead of === inside an if condition — Writing if (userScore = 100) accidentally sets userScore to 100 (assignment) instead of checking if it equals 100 (comparison). It won't throw an error — it silently evaluates as true for any truthy assigned value. Fix: always use === for comparisons inside conditions: if (userScore === 100).
- ✕Mistake 2: Using == instead of === and getting surprised by type coercion — Writing if (userInput == 0) will be true when userInput is 0 (number), '0' (string), '' (empty string), false, or null — because == coerces types. This causes logic bugs that are very hard to trace. Fix: use === which only returns true when both the value AND the type match exactly.
- ✕Mistake 3: Using || for default values when 0 or false are valid inputs — Writing const count = inputCount || 10 means if inputCount is 0 (a perfectly valid count), JavaScript treats 0 as falsy and assigns 10 instead. The bug is invisible until a user submits 0 and gets unexpected results. Fix: use the nullish coalescing operator instead: const count = inputCount ?? 10, which only falls back to 10 when inputCount is null or undefined.
Interview Questions on This Topic
- QWhat is the difference between == and === in JavaScript, and which one should you use in production code and why?
- QWhat does the nullish coalescing operator (??) do, and how is it different from using || for default values? Can you give an example where they produce different results?
- QWhat is the output of the following, and why: console.log(false == 0), console.log('' == false), console.log(null == undefined), console.log(null === undefined)?
Frequently Asked Questions
What is the difference between == and === in JavaScript?
== is loose equality — it converts both values to the same type before comparing, so '5' == 5 is true. === is strict equality — it compares both the value and the type with no conversion, so '5' === 5 is false. You should almost always use === in your code to avoid unexpected type-coercion bugs.
What does the % operator do in JavaScript?
The % operator is called modulus (or remainder). It divides the left number by the right number and returns whatever is left over after the division. For example, 10 % 3 returns 1 because 3 goes into 10 three times (9), leaving 1 remaining. It's commonly used to check if a number is even or odd: if (number % 2 === 0) means the number is even.
When should I use ?? instead of || in JavaScript?
Use ?? (nullish coalescing) when you want to provide a default value only if a variable is null or undefined. Use || only if you want ANY falsy value (including 0, false, and empty string '') to trigger the default. In practice, ?? is safer for defaults because 0, false, and '' are often valid values that you don't want accidentally replaced.
Written and reviewed by senior developers with real-world experience across enterprise, startup and open-source projects. Every article on TheCodeForge is written to be clear, accurate and genuinely useful — not just SEO filler.