Operators
Learn JavaScript's major categories of operators — arithmetic, assignment, comparison, equality, logical, nullish coalescing, optional chaining, unary, ternary, bitwise, exponentiation — plus typeof, instanceof, in, and delete.
Operators are the symbols and keywords JavaScript uses to combine, compare, and manipulate values — from simple math to modern conveniences for safely working with objects that might be missing data.
Arithmetic and assignment operators
Arithmetic operators perform math: + (addition, or string concatenation), - (subtraction), * (multiplication), / (division), % (remainder/modulo, the leftover after division), and ` (exponentiation, e.g. 2 3 is 8, equivalent to but more concise than Math.pow(2, 3)`).
Assignment operators store a value into a variable. The plain = simply assigns. Compound assignment operators combine an operation with assignment in one step: x += 5 means x = x + 5; the same shorthand pattern works for -=, *=, /=, %=, **=, and even logical assignment like ||=, &&=, and ??=.
Comparison and equality operators
Comparison operators compare two values and produce a boolean: <, >, <=, >=. When comparing values of different types, JavaScript may coerce them first (following the same rules covered in the previous lesson), so it's worth being careful when comparing, say, a string to a number.
Equality operators check if two values are considered equal: == (loose, coerces types first) and === (strict, no coercion — checks type and value). Their opposites are != (loose not-equal) and !== (strict not-equal). As covered previously, ===/!== are the recommended default.
Logical operators, nullish coalescing, and optional chaining
Logical operators combine or invert boolean logic: && (AND — true only if both sides are truthy, and returns the first falsy value or the last value), || (OR — true if either side is truthy, and returns the first truthy value or the last value), and ! (NOT — inverts a boolean).
The nullish coalescing operator ?? returns its right-hand value only when the left-hand value is specifically null or undefined (not just any falsy value) — this fixes a common || pitfall where a legitimate value like 0 or "" gets incorrectly replaced with a fallback. let count = userCount ?? 10; keeps userCount if it is 0, unlike userCount || 10, which would incorrectly fall back to 10.
Optional chaining ?. safely accesses a nested property or calls a method, automatically short-circuiting to undefined instead of throwing an error if something along the chain is null or undefined — user?.address?.city returns undefined instead of crashing if user or user.address doesn't exist.
Unary, ternary, and exponentiation operators
A unary operator acts on a single operand: -x (negation), +x (attempts to convert x to a number, similar to Number(x)), !x (logical NOT), and typeof x. Increment/decrement (++, --) are also unary, adding or subtracting 1 from a variable.
The conditional (ternary) operator condition ? valueIfTrue : valueIfFalse is JavaScript's only operator that takes three operands, and it offers a compact alternative to a simple if/else when you just need to pick between two values: let status = age >= 18 ? "adult" : "minor";.
Exponentiation ` raises a number to a power, as mentioned above: 5 2 is 25. It was introduced in ES2016 as a more readable replacement for Math.pow()`.
Bitwise operators and special keyword operators
Bitwise operators (&, |, ^, ~, <<, >>, >>>) operate on the individual binary bits of numbers. They are used far less often in everyday application code than arithmetic operators, but appear in performance-sensitive code, flags/permission systems, and low-level tasks like graphics or networking.
JavaScript also has several keyword-based operators: typeof value returns a value's type as a string (covered in the previous lesson); instanceof checks whether an object is an instance of a particular class/constructor, e.g. [] instanceof Array is true; in checks whether a property name exists in an object (or its prototype chain), e.g. "age" in user; and delete removes a property from an object entirely, e.g. delete user.age.
Operator cheat sheet
?? and || look similar but differ on 0, "", and false: ?? only falls back on null/undefined, || falls back on any falsy value. Optional chaining (?.) can be combined with nullish coalescing: user?.age ?? "unknown". delete only works on object properties, not on variables declared with let/const/var.
// Arithmetic & assignment
let x = 10;
x += 5; // 15
let power = 2 ** 3; // 8
// Comparison & equality
5 > 3; // true
"5" === 5; // false
// Logical, nullish coalescing, optional chaining
true && false; // false
null ?? "default"; // "default"
user?.profile?.bio; // undefined if any part is missing, no crash
// Ternary
let label = x > 10 ? "big" : "small";
// Keyword operators
typeof x; // "number"
[] instanceof Array; // true
"name" in { name: 1 }; // true
delete someObject.key; // removes the propertyCode Examples
This combines a compound assignment operator, an increment operator, and a ternary operator in one small, realistic example. Expected result: 19.99 4 cart updated cart.total += 19.99; is shorthand for cart.total = cart.total + 19.99;
This shows optional chaining and nullish coalescing working together to safely read a deeply nested property that might not exist, without ever throwing an error. Expected result: Austin City unknown City unknown user?.address?.city ?? "City unknown" — chains safely through possibly-missing levels, then falls back only if the final result is null or undefined.
Common mistake: Writing user.address.city without optional chaining would throw "Cannot read properties of undefined" the moment address (or user) is missing.
let cart = { items: 3, total: 0 };
cart.total += 19.99;
cart.items++;
console.log(cart.total, cart.items);
console.log(cart.items > 3 ? "cart updated" : "no change");function getCity(user) {
return user?.address?.city ?? "City unknown";
}
console.log(getCity({ address: { city: "Austin" } }));
console.log(getCity({}));
console.log(getCity(null));|| vs ?? fallback behavior
|| replaces ANY falsy value with the fallback; ?? replaces ONLY null and undefined, preserving legitimate falsy values like 0, "", and false.
value value || "fallback" value ?? "fallback"
----------------------------------------------------------
0 "fallback" 0
"" "fallback" ""
false "fallback" false
null "fallback" "fallback"
undefined "fallback" "fallback"Important Rules
Use === / !== for equality; reserve == / != only for deliberate, well-understood coercion cases.
Use ?? instead of || when 0, "", or false are valid values you don't want accidentally replaced by a fallback.
Use optional chaining (?.) when accessing nested properties that might not exist, to avoid runtime errors.
The ternary operator is best for simple, single-expression choices — prefer if/else for more complex branching logic.
delete removes an object property entirely (and 'name' in obj afterward becomes false); it does not work on variables.
Where this shows up
Optional chaining and nullish coalescing are used constantly in real applications when working with data from APIs, where fields might be missing or null — safely reading user?.settings?.theme ?? "light" is far more robust than a chain of manual if-checks.
let quantity = productQuantity || 1; // if productQuantity is legitimately 0, this becomes 1 let quantity = productQuantity ?? 1; // only falls back when productQuantity is null or undefined
|| treats 0 as falsy and replaces it with the fallback, which is wrong when 0 is a meaningful, valid quantity; ?? only reacts to null/undefined.
[Multiple Choice] What is the key difference between the || and ?? operators? A. There is no difference; they are interchangeable B. ?? only falls back on null or undefined; || falls back on any falsy value including 0, "", and false C. || only works with numbers; ?? only works with strings D. ?? is only used in comparisons, never in assignments
B. ?? only falls back on null or undefined; || falls back on any falsy value including 0, "", and false — || treats any falsy value (0, "", false, null, undefined, NaN) as a reason to use the fallback, while ?? reacts only to null or undefined, preserving other falsy-but-valid values.
[Predict the Output] What does console.log(user?.profile?.name) log if user is { profile: null }? A. An error is thrown B. undefined C. null D. "" (empty string)
B. undefined — user?.profile evaluates to null, and then null?.name short-circuits (because optional chaining stops on both null and undefined) and returns undefined instead of throwing.
Write a function isAdult(age) that uses the ternary operator to return "adult" if age is 18 or greater, and "minor" otherwise. Then write a function getTheme(settings) that safely returns settings.theme using optional chaining, falling back to "light" if it is missing.
function isAdult(age) { return age >= 18 ? "adult" : "minor"; } function getTheme(settings) { return settings?.theme ?? "light"; } console.log(isAdult(20)); // "adult" console.log(getTheme(undefined)); // "light" console.log(getTheme({ theme: "dark" })); // "dark"
Ternary: condition ? a : b. Safe access + fallback: obj?.prop ?? fallback.