JavaScript Operators
Operators are symbols that perform operations on values. JavaScript has arithmetic, comparison, logical, and assignment operators, plus modern ones like nullish coalescing.
Arithmetic Operators
Perform mathematical calculations on numbers:
// Basic arithmetic
let a = 10, b = 3;
a + b // 13 (addition)
a - b // 7 (subtraction)
a * b // 30 (multiplication)
a / b // 3.333... (division)
a % b // 1 (modulo/remainder)
a ** b // 1000 (exponentiation, 10^3)
// Increment and decrement
let count = 5;
count++ // 6 (post-increment)
++count // 7 (pre-increment)
count-- // 6 (post-decrement)
--count // 5 (pre-decrement)
// String concatenation with +
"Hello" + " " + "World" // "Hello World"
"Age: " + 25 // "Age: 25"+ operator also concatenates strings. If one operand is a string, the other is converted: "5" + 3 gives "53". Comparison Operators
Compare values and return a boolean:
// Equality operators
5 == "5" // true (loose, converts types)
5 === "5" // false (strict, different types)
5 != "5" // false
5 !== "5" // true
// Relational operators
5 > 3 // true
5 >= 5 // true
5 < 3 // false
5 <= 5 // true
// Comparing strings (alphabetically)
"apple" < "banana" // true
"A" < "a" // true (uppercase before lowercase)
// Comparing with null/undefined
null == undefined // true
null === undefined // false== vs === (The Golden Rule)
| Expression | == (loose) | === (strict) |
|---|---|---|
| 5 and "5" | ||
| 0 and false | ||
| 0 and "" | ||
| null and undefined | ||
| [] and false | ||
| "" and false |
==) performs type coercion which leads to surprising results. Always use strict equality (===) to compare both value and type. Logical Operators
Combine or invert boolean values:
// AND (&&) - all must be true
true && true // true
true && false // false
false && true // false
// OR (||) - at least one must be true
true || false // true
false || true // true
false || false // false
// NOT (!) - inverts the value
!true // false
!false // true
!!0 // false (double negation converts to boolean)
!!"hi" // true
// Short-circuit evaluation
const user = null;
const name = user && user.name; // null (stops at falsy)
const defaultName = name || "Guest"; // "Guest"&& stops at the first falsy value. || stops at the first truthy value. This is useful for defaults and conditional execution. Assignment Operators
Assign values to variables, with optional operations:
let x = 10;
x += 5; // x = x + 5 (15)
x -= 3; // x = x - 3 (12)
x *= 2; // x = x * 2 (24)
x /= 4; // x = x / 4 (6)
x %= 4; // x = x % 4 (2)
x **= 3; // x = x ** 3 (8)
// Logical assignment (ES2021)
let a = null;
a ??= "default"; // a = a ?? "default" ("default")
let b = 0;
b ||= 10; // b = b || 10 (10, because 0 is falsy)
let c = 5;
c &&= 10; // c = c && 10 (10, because 5 is truthy)Ternary Operator
A shorthand for simple if-else statements:
// Ternary operator: condition ? ifTrue : ifFalse
const age = 20;
const status = age >= 18 ? "adult" : "minor";
console.log(status); // "adult"
// Equivalent if-else
let status2;
if (age >= 18) {
status2 = "adult";
} else {
status2 = "minor";
}
// Nested ternary (use sparingly!)
const score = 85;
const grade = score >= 90 ? "A"
: score >= 80 ? "B"
: score >= 70 ? "C"
: "F";
console.log(grade); // "B"Nullish Coalescing & Optional Chaining
Modern operators for handling null/undefined values safely:
// Nullish coalescing (??)
// Returns right side ONLY for null/undefined
const value1 = null ?? "default"; // "default"
const value2 = undefined ?? "default"; // "default"
const value3 = 0 ?? "default"; // 0 (not nullish!)
const value4 = "" ?? "default"; // "" (not nullish!)
const value5 = false ?? "default"; // false (not nullish!)
// Compare with ||
const a = 0 || "default"; // "default" (0 is falsy)
const b = 0 ?? "default"; // 0 (0 is not nullish)
// Optional chaining (?.)
const user = { name: "Alice" };
user?.name // "Alice"
user?.address // undefined (no error)
user?.address?.city // undefined (no error)
// Combined with nullish coalescing
const city = user?.address?.city ?? "Unknown"; // "Unknown"?? when 0, "", or false are valid values. Use || only when you want to replace all falsy values. Try It Yourself
Experiment with different operators:
// Arithmetic Operators
console.log("=== Arithmetic ===");
console.log("5 + 3 =", 5 + 3); // 8
console.log("5 - 3 =", 5 - 3); // 2
console.log("5 * 3 =", 5 * 3); // 15
console.log("5 / 3 =", 5 / 3); // 1.666...
console.log("5 % 3 =", 5 % 3); // 2 (remainder)
console.log("5 ** 3 =", 5 ** 3); // 125 (exponent)
// Comparison Operators
console.log("\n=== Comparison ===");
console.log("5 == '5':", 5 == '5'); // true (loose)
console.log("5 === '5':", 5 === '5'); // false (strict)
console.log("5 > 3:", 5 > 3); // true
console.log("5 >= 5:", 5 >= 5); // true
console.log("5 != '5':", 5 != '5'); // false
console.log("5 !== '5':", 5 !== '5'); // true
// Logical Operators
console.log("\n=== Logical ===");
console.log("true && false:", true && false); // false
console.log("true || false:", true || false); // true
console.log("!true:", !true); // false
// Assignment Operators
console.log("\n=== Assignment ===");
let x = 10;
x += 5; console.log("x += 5:", x); // 15
x -= 3; console.log("x -= 3:", x); // 12
x *= 2; console.log("x *= 2:", x); // 24
x /= 4; console.log("x /= 4:", x); // 6See how short-circuit evaluation and nullish coalescing differ:
// Short-circuit with ||
console.log("=== OR (||) - returns first truthy ===");
console.log(null || "default"); // "default"
console.log(0 || "default"); // "default" (0 is falsy!)
console.log("" || "default"); // "default" (empty string is falsy!)
console.log("hello" || "default"); // "hello"
// Short-circuit with &&
console.log("\n=== AND (&&) - returns first falsy ===");
console.log(true && "hello"); // "hello"
console.log(false && "hello"); // false
console.log("hi" && "hello"); // "hello"
// Nullish coalescing (??) - only null/undefined
console.log("\n=== Nullish (??) - only null/undefined ===");
console.log(null ?? "default"); // "default"
console.log(undefined ?? "default"); // "default"
console.log(0 ?? "default"); // 0 (0 is NOT nullish!)
console.log("" ?? "default"); // "" (empty string is NOT nullish!)
// Optional chaining (?.)
console.log("\n=== Optional Chaining (?.) ===");
const user = { name: "Alice", address: { city: "NYC" } };
console.log(user?.name); // "Alice"
console.log(user?.address?.city); // "NYC"
console.log(user?.phone?.number); // undefined (no error!)Best Practices
==. 0, "", or false are valid values, use ?? instead of ||. ?.) prevents "Cannot read property of undefined" errors. Test Your Knowledge
Test Your Knowledge
5 questionsWhat does 5 === "5" return?
What does null ?? "default" return?
What does 0 || "default" return?
What does 10 % 3 return?
What does true && false || true return?
Practice Exercises
Challenge 1: Safe Division
Create a function that safely divides two numbers, returning 0 for invalid inputs or division by zero.
// Challenge: Create a function that safely divides two numbers
// Return 0 if dividing by zero, and handle non-number inputs
function safeDivide(a, b) {
// TODO: Return a / b, but:
// - Return 0 if b is 0 (avoid division by zero)
// - Return 0 if either a or b is not a number
// - Return the result otherwise
}
console.log(safeDivide(10, 2)); // should print 5
console.log(safeDivide(10, 0)); // should print 0
console.log(safeDivide("10", 2)); // should print 0
console.log(safeDivide(10, "2")); // should print 0
console.log(safeDivide(0, 5)); // should print 0
Challenge 2: Config with Defaults
Create a function that gets config values with defaults, preserving valid falsy values like 0 and false.
// Challenge: Create a function that gets a config value with defaults
// Use nullish coalescing and optional chaining
function getConfig(config, key, defaultValue) {
// TODO: Return config[key] if it exists and is not null/undefined
// Otherwise return defaultValue
// Handle cases where config itself might be null/undefined
}
const config = {
theme: "dark",
fontSize: 0, // 0 is a valid value!
showTips: false, // false is a valid value!
username: null
};
console.log(getConfig(config, "theme", "light")); // should print "dark"
console.log(getConfig(config, "fontSize", 14)); // should print 0 (not 14!)
console.log(getConfig(config, "showTips", true)); // should print false (not true!)
console.log(getConfig(config, "username", "Guest")); // should print "Guest"
console.log(getConfig(config, "language", "en")); // should print "en"
console.log(getConfig(null, "theme", "light")); // should print "light"
Frequently Asked Questions
What is operator precedence?
Operators have different priorities. Multiplication happens before addition (2 + 3 * 4 = 14, not 20). Use parentheses to make intent clear: (2 + 3) * 4 = 20.
When should I use ++ vs += 1?
Both work, but += 1 is clearer. The difference between x++ and ++x (post vs pre-increment) can cause bugs. Many style guides prefer += 1 for clarity.
Can I chain optional chaining?
Yes! user?.address?.city?.name safely accesses deeply nested properties. If any part is null or undefined, the whole expression returns undefined instead of throwing an error.
What are bitwise operators?
Bitwise operators (&, |, ^, ~, <<, >>) work on binary representations of numbers. They're rarely used in typical JavaScript but are useful for flags and low-level operations.
Summary
JavaScript operators let you manipulate values in different ways:
- Arithmetic: +, -, *, /, %, ** for math operations
- Comparison: ===, !==, <, >, <=, >= for comparisons
- Logical: &&, ||, ! for boolean logic
- Assignment: =, +=, -=, etc. for assigning values
- Ternary: condition ? a : b for inline conditionals
- Nullish: ?? and ?. for safe null/undefined handling
Key takeaways:
- Always use
===instead of== - Use
??when 0, "", or false are valid values - Use
?.to safely access nested properties