Arithmetic Operators
Standard math operations plus a few JavaScript-specific ones:
console.log(10 + 3); // 13 - addition
console.log(10 - 3); // 7 - subtraction
console.log(10 * 3); // 30 - multiplication
console.log(10 / 3); // 3.3333... - division (always float)
console.log(10 % 3); // 1 - modulus (remainder)
console.log(2 ** 10); // 1024 - exponentiation (ES2016)
// Increment and 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
// Unary plus and minus
console.log(+"42"); // 42 - convert string to number
console.log(-"42"); // -42
console.log(+true); // 1
console.log(+false); // 0
console.log(+null); // 0
console.log(+undefined); // NaN
// + with strings (concatenation - not addition)
console.log("5" + 3); // "53" (string concat)
console.log(5 + "3"); // "53"
console.log(5 - "3"); // 2 (- always coerces to number)
Assignment Operators
Shorthand operators that combine assignment with another operation:
let n = 10;
n += 5; // n = n + 5 -> 15
n -= 3; // n = n - 3 -> 12
n *= 2; // n = n * 2 -> 24
n /= 4; // n = n / 4 -> 6
n %= 4; // n = n % 4 -> 2
n **= 3; // n = n ** 3 -> 8
// Logical assignment (ES2021)
let a = null;
a ??= "default"; // assign only if null or undefined
console.log(a); // "default"
let b = 0;
b ||= 42; // assign if left side is falsy
console.log(b); // 42
let c = 1;
c &&= 99; // assign if left side is truthy
console.log(c); // 99
Comparison Operators
Comparisons return true or false. The critical rule:
always use === (strict), never == (loose).
// Strict equality (===) - checks value AND type
console.log(5 === 5); // true
console.log(5 === "5"); // false - different types
console.log(null === null); // true
// Strict inequality (!==)
console.log(5 !== "5"); // true
console.log(5 !== 5); // false
// Relational
console.log(5 > 3); // true
console.log(5 >= 5); // true
console.log(3 < 5); // true
console.log(3 <= 2); // false
// String comparison (lexicographic)
console.log("banana" > "apple"); // true (b > a)
console.log("10" > "9"); // false! ("1" < "9" lexicographically)
console.log(10 > 9); // true (numeric)
// Loose equality == - avoid!
console.log(0 == false); // true (coerces false to 0)
console.log("" == false); // true (both coerce to 0)
console.log(null == undefined); // true (special case)
console.log(null == false); // false (null only == undefined)
console.log(NaN == NaN); // false (NaN never equals anything)
Logical Operators
&&, ||, and ! are the three logical operators.
Importantly, && and || do not return true/false
- they return one of their operands.
// && (AND) - returns first falsy value, or last value if all truthy
console.log(true && true); // true
console.log(true && false); // false
console.log(1 && 2); // 2 (1 is truthy, so return last: 2)
console.log(0 && 2); // 0 (0 is falsy, short-circuit here)
console.log("a" && "b"); // "b"
// || (OR) - returns first truthy value, or last value if all falsy
console.log(false || true); // true
console.log(0 || 42); // 42 (0 is falsy, return next: 42)
console.log("" || "default"); // "default"
console.log("hello" || "x"); // "hello" (first truthy wins)
// ! (NOT) - converts to boolean and inverts
console.log(!true); // false
console.log(!0); // true
console.log(!""); // true
console.log(!"hello"); // false
console.log(!!0); // false (double NOT = boolean cast)
console.log(!!"text"); // true
// Short-circuit evaluation
const user = null;
user && console.log(user.name); // safe - right side never runs
const port = process.env.PORT || 3000; // common default pattern
A classic pattern: const name = inputName || "Guest" uses short-circuit to provide a default. The caveat: || treats 0, "", and false as falsy too. If those are valid values, use ?? instead: const count = inputCount ?? 0.
Nullish Coalescing (??)
The ?? operator returns the right-hand side only when the left side is
null or undefined - not for 0, false, or empty string.
// ?? vs || comparison
const a = 0;
console.log(a || 10); // 10 (|| treats 0 as falsy - may not be intended)
console.log(a ?? 10); // 0 (?? only triggers for null/undefined)
const b = "";
console.log(b || "default"); // "default" (|| treats "" as falsy)
console.log(b ?? "default"); // "" (?? keeps empty string)
const c = null;
console.log(c ?? "fallback"); // "fallback"
const d = undefined;
console.log(d ?? "fallback"); // "fallback"
// Practical use: user settings where 0 is valid
function getTimeout(config) {
return config.timeout ?? 5000; // 0ms timeout is valid, do not replace with 5000
}
// Nullish assignment ??= (ES2021)
let settings = { theme: null };
settings.theme ??= "light"; // only sets if null or undefined
console.log(settings.theme); // "light"
Optional Chaining (?.)
The ?. operator short-circuits to undefined if the left side is
null or undefined, instead of throwing a TypeError.
const user = {
name: "Alice",
address: {
city: "London"
}
};
// Without optional chaining - crashes if address is missing
// const city = user.location.city; // TypeError!
// With optional chaining
console.log(user?.address?.city); // "London"
console.log(user?.phone?.number); // undefined (no crash)
// Optional chaining with methods
const arr = null;
console.log(arr?.map(x => x * 2)); // undefined (no crash)
// Optional chaining with bracket notation
const key = "name";
console.log(user?.[key]); // "Alice"
// Combine with ?? for a default
const city = user?.address?.city ?? "Unknown";
console.log(city); // "London"
const phone = user?.phone?.number ?? "No phone";
console.log(phone); // "No phone"
Ternary Operator
The ternary operator is a compact alternative to if/else for simple
conditional expressions. Syntax: condition ? valueIfTrue : valueIfFalse
const age = 20;
// Basic ternary
const status = age >= 18 ? "adult" : "minor";
console.log(status); // "adult"
// Equivalent if/else
let status2;
if (age >= 18) {
status2 = "adult";
} else {
status2 = "minor";
}
// Ternary in template literals
const name = "Alice";
console.log(`Hello, ${name ? name : "Guest"}!`); // "Hello, Alice!"
// Nested ternary - use sparingly (hard to read)
const score = 75;
const grade = score >= 90 ? "A"
: score >= 80 ? "B"
: score >= 70 ? "C"
: "F";
console.log(grade); // "C"
// Better: use if/else or a lookup object for complex cases
Operator Precedence
When multiple operators appear in one expression, JavaScript evaluates them in order of precedence (highest first). When in doubt, use parentheses.
| Priority | Operators | Example |
|---|---|---|
| Highest | () | (2 + 3) * 4 |
| High | ** | 2 ** 3 = 8 |
| High | * / % | 3 * 4 / 2 |
| Mid | + - | 3 + 4 - 1 |
| Mid | < > <= >= | a > b |
| Mid | === !== == != | a === b |
| Low | && | a && b |
| Low | || | a || b |
| Low | ?? | a ?? b |
| Lowest | = += -= etc. | assignment |
// Precedence in action
console.log(2 + 3 * 4); // 14 (not 20 - * before +)
console.log((2 + 3) * 4); // 20 - parentheses override
console.log(true || false && false); // true (&& before ||)
// reads as: true || (false && false) -> true || false -> true
// When mixing && and ||, be explicit with parentheses
const a = true, b = false, c = true;
const result = (a || b) && c; // clear intent