JavaScript Operators: Complete Guide for Developers
Master JavaScript operators: arithmetic, comparison, logical, assignment, bitwise, ternary, nullish coalescing, optional chaining with detailed examples and best practices.
JavaScript Operators: Complete Guide for Developers
📋 Table of Contents
- What are JavaScript Operators?
- Why Do We Need Operators?
- Real-World Use Cases
- Syntax
- Internal Working
- Memory Diagram
- Data Flow Diagram
- Code Examples
- Common Mistakes
- Performance Considerations
- Interview Questions
- Cheat Sheet
- Summary
1. What are JavaScript Operators?
Operators are special symbols that perform operations on operands (values and variables). They are the building blocks for creating expressions and manipulating data.
Operator Categories
┌─────────────────────────────────────────────────────────────┐
│ JAVASCRIPT OPERATORS │
└─────────────────────────────────────────────────────────────┘
JavaScript Operators
|
┌────┴────────────────────────────────┐
| |
├─ Arithmetic (+, -, *, /, %, **)
├─ Assignment (=, +=, -=, *=, /=)
├─ Comparison (==, ===, !=, !==, >, <, >=, <=)
├─ Logical (&&, ||, !)
├─ Bitwise (&, |, ^, ~, <<, >>, >>>)
├─ String (+, template literals)
├─ Conditional (? :)
├─ Type (typeof, instanceof, in, delete)
├─ Nullish Coalescing (??)
├─ Optional Chaining (?.)
├─ Spread/Rest (...)
└─ Comma (,)
Operator Terminology
┌─────────────────────────────────────────────────────────────┐
│ OPERATOR TERMINOLOGY │
├─────────────────────────────────────────────────────────────┤
│ │
│ Expression: 10 + 20 │
│ ↑ ↑ ↑ │
│ │ │ └─ Operand (right) │
│ │ └──── Operator │
│ └──────── Operand (left) │
│ │
│ Unary Operator: One operand (++x, !flag) │
│ Binary Operator: Two operands (a + b, x > y) │
│ Ternary Operator: Three operands (a ? b : c) │
│ │
└─────────────────────────────────────────────────────────────┘
2. Why Do We Need Operators?
Operators make code concise, readable, and expressive.
Without Operators (Verbose)
// Hypothetical world without operators
let sum = add(10, 20);
let isGreater = greaterThan(x, y);
let result = ifThenElse(condition, trueValue, falseValue);
With Operators (Concise)
// Real JavaScript with operators
let sum = 10 + 20;
let isGreater = x > y;
let result = condition ? trueValue : falseValue;
3. Real-World Use Cases
1. E-commerce Price Calculation
const price = 99.99;
const quantity = 3;
const taxRate = 0.08;
const subtotal = price * quantity; // Arithmetic
const tax = subtotal * taxRate; // Arithmetic
const total = subtotal + tax; // Arithmetic
const discount = total >= 200 ? 20 : 0; // Conditional
const finalPrice = total - discount; // Arithmetic
console.log(`Final Price: $${finalPrice.toFixed(2)}`);
2. User Authentication
const user = {
username: "john_doe",
age: 25,
isActive: true,
roles: ["user", "editor"]
};
// Logical operators for access control
const canEdit = user.isActive && user.roles.includes("editor");
const canView = user.isActive || user.roles.includes("guest");
const isAdult = user.age >= 18;
// Optional chaining for safe property access
const city = user?.address?.city ?? "Unknown";
3. Data Validation
function validateUser(user) {
// Nullish coalescing for defaults
const name = user?.name ?? "Anonymous";
const age = user?.age ?? 0;
// Comparison operators
const isValidAge = age >= 18 && age <= 120;
const hasValidName = name.length > 0 && name.length <= 50;
// Logical operators
return isValidAge && hasValidName;
}
4. Syntax
Arithmetic Operators
// Basic arithmetic
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)
// Increment/Decrement
let x = 5;
console.log(x++); // 5 (post-increment: use then increment)
console.log(x); // 6
console.log(++x); // 7 (pre-increment: increment then use)
console.log(x--); // 7 (post-decrement)
console.log(--x); // 5 (pre-decrement)
Assignment Operators
let num = 10;
num += 5; // num = num + 5 → 15
num -= 3; // num = num - 3 → 12
num *= 2; // num = num * 2 → 24
num /= 4; // num = num / 4 → 6
num %= 4; // num = num % 4 → 2
num **= 3; // num = num ** 3 → 8
// Logical assignment (ES2021)
let value = null;
value ??= 10; // value = value ?? 10
value ||= 20; // value = value || 20
value &&= 30; // value = value && 30
Comparison Operators
// Loose equality (with type coercion)
console.log(5 == "5"); // true
console.log(0 == false); // true
console.log(null == undefined); // true
// Strict equality (no type coercion)
console.log(5 === "5"); // false
console.log(0 === false); // false
console.log(null === undefined); // false
// Inequality
console.log(5 != "5"); // false (loose)
console.log(5 !== "5"); // true (strict)
// Relational
console.log(10 > 5); // true
console.log(10 < 5); // false
console.log(10 >= 10); // true
console.log(10 <= 5); // false
Logical Operators
// AND (&&) - both must be true
console.log(true && true); // true
console.log(true && false); // false
// OR (||) - at least one must be true
console.log(true || false); // true
console.log(false || false); // false
// NOT (!) - inverts boolean
console.log(!true); // false
console.log(!false); // true
console.log(!!0); // false (double negation)
console.log(!!"hello"); // true
Ternary Operator
// Syntax: condition ? valueIfTrue : valueIfFalse
const age = 20;
const status = age >= 18 ? "Adult" : "Minor";
// Nested ternary (use sparingly)
const grade = score >= 90 ? "A" :
score >= 80 ? "B" :
score >= 70 ? "C" : "F";
Nullish Coalescing (??)
// Returns right operand when left is null or undefined
const value1 = null ?? "default"; // "default"
const value2 = undefined ?? "default"; // "default"
const value3 = 0 ?? "default"; // 0 (not null/undefined)
const value4 = "" ?? "default"; // "" (not null/undefined)
const value5 = false ?? "default"; // false (not null/undefined)
Optional Chaining (?.)
const user = {
name: "John",
address: {
city: "New York"
}
};
// Safe property access
console.log(user?.name); // "John"
console.log(user?.address?.city); // "New York"
console.log(user?.address?.zip); // undefined (no error)
console.log(user?.contact?.phone); // undefined (no error)
// Safe method call
console.log(user?.getName?.()); // undefined (no error)
// Safe array access
const arr = [1, 2, 3];
console.log(arr?.[0]); // 1
console.log(arr?.[10]); // undefined
5. Internal Working
Operator Precedence
┌─────────────────────────────────────────────────────────────┐
│ OPERATOR PRECEDENCE (High to Low) │
└─────────────────────────────────────────────────────────────┘
Priority Operator Example
──────── ──────────────────── ─────────────────
20 Grouping (...)
19 Member Access obj.prop, obj[prop]
19 Optional Chaining obj?.prop
18 new (with args) new Func(args)
17 Function Call func()
16 Postfix Inc/Dec x++, x--
15 Prefix Inc/Dec ++x, --x
15 Logical NOT !x
15 typeof, delete typeof x, delete obj.prop
14 Exponentiation x ** y
13 Multiplication x * y, x / y, x % y
12 Addition x + y, x - y
11 Bitwise Shift x << y, x >> y
10 Relational x < y, x > y, x <= y, x >= y
10 in, instanceof prop in obj, obj instanceof Class
9 Equality x == y, x === y, x != y, x !== y
8 Bitwise AND x & y
7 Bitwise XOR x ^ y
6 Bitwise OR x | y
5 Logical AND x && y
4 Logical OR x || y
3 Nullish Coalescing x ?? y
2 Conditional x ? y : z
1 Assignment x = y, x += y, x &&= y
0 Comma x, y
Short-Circuit Evaluation
// AND (&&) - stops at first falsy value
false && console.log("Never runs"); // false (short-circuit)
true && console.log("Runs"); // Runs
// OR (||) - stops at first truthy value
true || console.log("Never runs"); // true (short-circuit)
false || console.log("Runs"); // Runs
// Practical use
function greet(name) {
name = name || "Guest"; // Default value
console.log(`Hello, ${name}`);
}
6. Memory Diagram
┌─────────────────────────────────────────────────────────────┐
│ OPERATOR EVALUATION IN MEMORY │
└─────────────────────────────────────────────────────────────┘
Expression: let result = (10 + 20) * 2;
Step 1: Parse Expression
────────────────────────
*
/ \
+ 2
/ \
10 20
Step 2: Evaluate (10 + 20)
──────────────────────────
Stack:
┌──────────┐
│ 10 │ Push 10
├──────────┤
│ 20 │ Push 20
├──────────┤
│ 30 │ Pop both, add, push result
└──────────┘
Step 3: Evaluate 30 * 2
───────────────────────
Stack:
┌──────────┐
│ 30 │ Previous result
├──────────┤
│ 2 │ Push 2
├──────────┤
│ 60 │ Pop both, multiply, push result
└──────────┘
Step 4: Assign to result
─────────────────────────
Stack:
┌──────────────┐
│ result: 60 │ Store in variable
└──────────────┘
7. Data Flow Diagram
┌─────────────────────────────────────────────────────────────┐
│ COMPARISON OPERATOR FLOW │
└─────────────────────────────────────────────────────────────┘
Expression: 5 === "5"
┌──────────┐
│ Operand 1│
│ (5) │
└────┬─────┘
│
v
┌──────────────┐
│ Get Type │
│ typeof 5 │
│ → "number" │
└────┬─────────┘
│
v
┌──────────┐
│ Operand 2│
│ ("5") │
└────┬─────┘
│
v
┌──────────────┐
│ Get Type │
│ typeof "5" │
│ → "string" │
└────┬─────────┘
│
v
┌──────────────┐
│ Compare Types│
│ number ≠ │
│ string │
└────┬─────────┘
│
v
┌──────────────┐
│ Result │
│ false │
└──────────────┘
┌─────────────────────────────────────────────────────────────┐
│ LOGICAL AND (&&) FLOW │
└─────────────────────────────────────────────────────────────┘
Expression: condition1 && condition2 && condition3
┌──────────────┐
│ Evaluate │
│ condition1 │
└────┬─────────┘
│
├─ false ──→ Return false (short-circuit)
│
v true
┌──────────────┐
│ Evaluate │
│ condition2 │
└────┬─────────┘
│
├─ false ──→ Return false (short-circuit)
│
v true
┌──────────────┐
│ Evaluate │
│ condition3 │
└────┬─────────┘
│
v
┌──────────────┐
│ Return │
│ condition3 │
│ result │
└──────────────┘
8. Code Examples
Example 1: Arithmetic Operations
// Calculator function
function calculate(a, b, operator) {
switch(operator) {
case '+': return a + b;
case '-': return a - b;
case '*': return a * b;
case '/': return b !== 0 ? a / b : "Division by zero";
case '%': return a % b;
case '**': return a ** b;
default: return "Invalid operator";
}
}
console.log(calculate(10, 3, '+')); // 13
console.log(calculate(10, 3, '**')); // 1000
console.log(calculate(10, 0, '/')); // "Division by zero"
Example 2: Comparison and Logical Operators
// User access control
function checkAccess(user) {
const isAuthenticated = user !== null && user !== undefined;
const isActive = user?.isActive === true;
const hasRole = user?.roles?.includes("admin") ||
user?.roles?.includes("editor");
const isVerified = user?.emailVerified === true;
// Complex condition
const canAccess = isAuthenticated &&
isActive &&
(hasRole || isVerified);
return {
canAccess,
reason: !isAuthenticated ? "Not authenticated" :
!isActive ? "Account inactive" :
!hasRole && !isVerified ? "Insufficient permissions" :
"Access granted"
};
}
const user = {
isActive: true,
roles: ["editor"],
emailVerified: true
};
console.log(checkAccess(user));
// { canAccess: true, reason: "Access granted" }
Example 3: Nullish Coalescing vs OR
// Demonstrating the difference
function displayValue(value) {
// Using OR (||) - treats 0, "", false as falsy
const withOR = value || "default";
// Using Nullish Coalescing (??) - only null/undefined
const withNullish = value ?? "default";
return { withOR, withNullish };
}
console.log(displayValue(0));
// { withOR: "default", withNullish: 0 }
console.log(displayValue(""));
// { withOR: "default", withNullish: "" }
console.log(displayValue(false));
// { withOR: "default", withNullish: false }
console.log(displayValue(null));
// { withOR: "default", withNullish: "default" }
Example 4: Optional Chaining
// API response handling
function getUserCity(response) {
// Without optional chaining (verbose)
const city1 = response &&
response.data &&
response.data.user &&
response.data.user.address &&
response.data.user.address.city;
// With optional chaining (concise)
const city2 = response?.data?.user?.address?.city;
return city2 ?? "City not available";
}
const response1 = {
data: {
user: {
address: {
city: "New York"
}
}
}
};
const response2 = {
data: {
user: null
}
};
console.log(getUserCity(response1)); // "New York"
console.log(getUserCity(response2)); // "City not available"
Example 5: Bitwise Operators
// Practical bitwise operations
class Permissions {
static READ = 1; // 0001
static WRITE = 2; // 0010
static EXECUTE = 4; // 0100
static DELETE = 8; // 1000
constructor() {
this.permissions = 0;
}
// Add permission
grant(permission) {
this.permissions |= permission; // Bitwise OR
}
// Remove permission
revoke(permission) {
this.permissions &= ~permission; // Bitwise AND with NOT
}
// Check permission
has(permission) {
return (this.permissions & permission) === permission;
}
}
const userPerms = new Permissions();
userPerms.grant(Permissions.READ);
userPerms.grant(Permissions.WRITE);
console.log(userPerms.has(Permissions.READ)); // true
console.log(userPerms.has(Permissions.DELETE)); // false
userPerms.revoke(Permissions.WRITE);
console.log(userPerms.has(Permissions.WRITE)); // false
9. Common Mistakes
Mistake 1: Assignment in Condition
// ❌ Wrong: Assignment instead of comparison
let x = 5;
if (x = 10) { // Always true! Assigns 10 to x
console.log("This always runs");
}
console.log(x); // 10 (modified!)
// ✅ Correct: Use comparison
let y = 5;
if (y === 10) { // Comparison
console.log("This doesn't run");
}
console.log(y); // 5 (unchanged)
Mistake 2: Using == Instead of ===
// ❌ Wrong: Loose equality causes unexpected results
console.log(0 == false); // true (type coercion)
console.log("" == false); // true
console.log(null == undefined); // true
console.log("5" == 5); // true
// ✅ Correct: Strict equality
console.log(0 === false); // false
console.log("" === false); // false
console.log(null === undefined);// false
console.log("5" === 5); // false
Mistake 3: Confusing || and ??
// ❌ Wrong: Using || for default values
function setConfig(options) {
const timeout = options.timeout || 5000;
// Problem: timeout of 0 will use 5000!
return timeout;
}
console.log(setConfig({ timeout: 0 })); // 5000 (wrong!)
console.log(setConfig({ timeout: 3000 })); // 3000 (correct)
// ✅ Correct: Using ?? for default values
function setConfigCorrect(options) {
const timeout = options.timeout ?? 5000;
// Only uses 5000 if timeout is null/undefined
return timeout;
}
console.log(setConfigCorrect({ timeout: 0 })); // 0 (correct!)
console.log(setConfigCorrect({ timeout: 3000 })); // 3000 (correct)
Mistake 4: Not Using Optional Chaining
// ❌ Wrong: Can throw error
function getCity(user) {
return user.address.city; // Error if address is undefined!
}
// ✅ Correct: Safe with optional chaining
function getCitySafe(user) {
return user?.address?.city ?? "Unknown";
}
const user1 = { address: { city: "NYC" } };
const user2 = { name: "John" };
console.log(getCitySafe(user1)); // "NYC"
console.log(getCitySafe(user2)); // "Unknown"
Mistake 5: Operator Precedence Confusion
// ❌ Wrong: Unexpected result due to precedence
const result1 = 10 + 5 * 2;
console.log(result1); // 20 (not 30!)
// Multiplication happens first: 10 + (5 * 2)
// ✅ Correct: Use parentheses for clarity
const result2 = (10 + 5) * 2;
console.log(result2); // 30
// Another example
const x = 5;
const y = 10;
const z = x > 3 && y < 20 || x === 10;
// Confusing! Better with parentheses:
const z2 = (x > 3 && y < 20) || (x === 10);
10. Performance Considerations
1. Short-Circuit Evaluation
// ✅ Fast: Short-circuit prevents unnecessary work
function expensiveCheck() {
console.log("Expensive operation");
return true;
}
const flag = false;
const result = flag && expensiveCheck(); // expensiveCheck never runs
2. Bitwise vs Arithmetic
// ✅ Faster: Bitwise operations
const doubled = 5 << 1; // 10 (bit shift)
const halved = 10 >> 1; // 5 (bit shift)
// ❌ Slower: Arithmetic operations
const doubled2 = 5 * 2; // 10
const halved2 = 10 / 2; // 5
// Note: Use bitwise only for integers and when performance matters
3. Avoid Repeated Property Access
// ❌ Slow: Multiple property accesses
for (let i = 0; i < array.length; i++) {
console.log(array[i]);
}
// ✅ Fast: Cache length
const len = array.length;
for (let i = 0; i < len; i++) {
console.log(array[i]);
}
11. Interview Questions
Q1: What's the difference between == and ===?
Answer:
==(loose equality): Compares values after type coercion===(strict equality): Compares both value and type without coercion
5 == "5" // true (string converted to number)
5 === "5" // false (different types)
Q2: Explain short-circuit evaluation.
Answer: JavaScript stops evaluating logical expressions once the result is determined:
&&: Stops at first falsy value||: Stops at first truthy value
false && expensiveFunction() // expensiveFunction never runs
true || expensiveFunction() // expensiveFunction never runs
Q3: What's the difference between || and ??
Answer:
||: Returns right operand if left is falsy (0, "", false, null, undefined, NaN)??: Returns right operand only if left is null or undefined
0 || 10 // 10 (0 is falsy)
0 ?? 10 // 0 (0 is not null/undefined)
Q4: What is optional chaining (?.) and when should you use it?
Answer: Optional chaining safely accesses nested properties without throwing errors if intermediate values are null/undefined.
user?.address?.city // Returns undefined if any part is null/undefined
// Instead of: user && user.address && user.address.city
Q5: Explain operator precedence with an example.
Answer: Operator precedence determines evaluation order. Higher precedence operators execute first.
10 + 5 * 2 // 20 (not 30)
// Multiplication (*) has higher precedence than addition (+)
// Evaluated as: 10 + (5 * 2)
(10 + 5) * 2 // 30
// Parentheses have highest precedence
Q6: What are bitwise operators and when are they useful?
Answer: Bitwise operators work on binary representations of numbers. Useful for:
- Permissions/flags
- Performance-critical operations
- Low-level programming
const READ = 1; // 0001
const WRITE = 2; // 0010
const perms = READ | WRITE; // 0011 (both permissions)
12. Cheat Sheet
// ═══════════════════════════════════════════════════════════
// OPERATORS QUICK REFERENCE
// ═══════════════════════════════════════════════════════════
// ARITHMETIC
// ──────────
+ // Addition
- // Subtraction
* // Multiplication
/ // Division
% // Modulus (remainder)
** // Exponentiation
++ // Increment
-- // Decrement
// ASSIGNMENT
// ──────────
= // Assign
+= // Add and assign
-= // Subtract and assign
*= // Multiply and assign
/= // Divide and assign
%= // Modulus and assign
**= // Exponent and assign
??= // Nullish coalescing assignment
||= // Logical OR assignment
&&= // Logical AND assignment
// COMPARISON
// ──────────
== // Loose equality
=== // Strict equality
!= // Loose inequality
!== // Strict inequality
> // Greater than
< // Less than
>= // Greater than or equal
<= // Less than or equal
// LOGICAL
// ───────
&& // AND (both must be true)
|| // OR (at least one must be true)
! // NOT (inverts boolean)
// CONDITIONAL
// ───────────
? : // Ternary (condition ? true : false)
// NULLISH & OPTIONAL
// ──────────────────
?? // Nullish coalescing (null/undefined check)
?. // Optional chaining (safe property access)
// TYPE
// ────
typeof // Get type of value
instanceof // Check if object is instance of class
in // Check if property exists in object
delete // Delete object property
// BITWISE
// ───────
& // AND
| // OR
^ // XOR
~ // NOT
<< // Left shift
>> // Right shift
>>> // Unsigned right shift
// BEST PRACTICES
// ──────────────
✓ Use === instead of ==
✓ Use ?? for default values (not ||)
✓ Use ?. for safe property access
✓ Use parentheses for clarity
✓ Understand operator precedence
✗ Avoid assignment in conditions
✗ Don't confuse = with ==
✗ Don't use == unless necessary
13. Summary
Key Takeaways
✅ Operators are symbols that perform operations on values
✅ === is preferred over == for comparisons
✅ Short-circuit evaluation optimizes logical operations
✅ ?? (nullish coalescing) only checks null/undefined
✅ ?. (optional chaining) safely accesses nested properties
✅ Operator precedence determines evaluation order
✅ Bitwise operators work on binary representations
✅ Ternary operator provides concise conditionals
✅ Type coercion happens with == but not ===
✅ Parentheses improve code clarity
Best Practices
- Always use === for equality checks
- Use ?? for default values instead of ||
- Use ?. for safe property access
- Understand operator precedence
- Use parentheses for complex expressions
- Leverage short-circuit evaluation
- Be aware of type coercion
- Use bitwise operators for performance when appropriate
Mastering JavaScript operators is essential for writing clean, efficient, and bug-free code.