Operators
Master arithmetic, comparison, logical, and nullish operators โ the tools that let you manipulate and combine values.
Arithmetic Operators
The basic math operators you know, plus a few extras:
console.log(10 + 4); // 14
console.log(10 - 4); // 6
console.log(10 * 4); // 40
console.log(10 / 4); // 2.5
console.log(10 % 4); // 2 (remainder/modulo)
console.log(2 ** 8); // 256 (exponentiation, ES7)
let x = 5;
x++; // increment: x is now 6
x--; // decrement: x is now 5
x += 10; // x = x + 10 โ 15
x -= 3; // x = x - 3 โ 12
x *= 2; // x = x * 2 โ 24
x /= 4; // x = x / 4 โ 6
Pre vs post increment:
let a = 5;
console.log(a++); // 5 โ returns value THEN increments
console.log(a); // 6
let b = 5;
console.log(++b); // 6 โ increments THEN returns value
console.log(b); // 6
Comparison Operators
Comparisons return a boolean (true or false):
console.log(5 > 3); // true
console.log(5 < 3); // false
console.log(5 >= 5); // true
console.log(5 <= 4); // false
console.log(5 === 5); // true (strict equality)
console.log(5 !== 3); // true (strict inequality)
Always use === and !== (strict equality). The loose versions (==, !=) coerce types:
5 == "5" // true โ coerces string to number
5 === "5" // false โ no coercion, different types
null == undefined // true โ surprising!
null === undefined // false โ correct
Logical Operators
// AND: both must be true
true && true // true
true && false // false
// OR: at least one must be true
true || false // true
false || false // false
// NOT: inverts the boolean
!true // false
!false // true
!!true // true (double negation = convert to boolean)
Short-circuit Evaluation
&& and || don't just work with booleans โ they short-circuit and return one of their operands:
// && returns first falsy value, or last value if all truthy
console.log(1 && 2 && 3); // 3
console.log(1 && 0 && 3); // 0 (stops at 0)
console.log(false && "hi"); // false
// || returns first truthy value, or last value if all falsy
console.log(0 || "" || "default"); // "default"
console.log(null || undefined || 42); // 42
console.log("hello" || "world"); // "hello"
This is used constantly for default values:
function greet(name) {
const displayName = name || "Guest";
console.log("Hello, " + displayName + "!");
}
greet("Alice"); // Hello, Alice!
greet(); // Hello, Guest!
Nullish Coalescing (??)
?? is like || but only falls back for null and undefined โ not 0, "", or false:
const count = 0;
// || problem: 0 is falsy, so it falls through
console.log(count || "no data"); // "no data" โ wrong!
// ?? only checks null/undefined
console.log(count ?? "no data"); // 0 โ correct!
const config = {
timeout: 0, // intentionally 0
retries: null, // not set
};
console.log(config.timeout ?? 3000); // 0 โ
console.log(config.retries ?? 3); // 3 โ
Optional Chaining (?.)
Access nested properties safely without checking each level manually:
const user = {
profile: {
address: {
city: "New York"
}
}
};
// Without optional chaining
const city1 = user && user.profile && user.profile.address && user.profile.address.city;
// With optional chaining โ much cleaner
const city2 = user?.profile?.address?.city;
console.log(city2); // "New York"
const noUser = null;
console.log(noUser?.profile?.city); // undefined (no error!)
// Works with methods too
const arr = null;
console.log(arr?.length); // undefined
console.log(arr?.map(x => x)); // undefined
Ternary Operator
A compact if-else expression:
const age = 20;
const status = age >= 18 ? "adult" : "minor";
console.log(status); // "adult"
// vs the equivalent if-else
let status2;
if (age >= 18) {
status2 = "adult";
} else {
status2 = "minor";
}
โ Tip
Ternaries are great for simple inline conditions. For complex logic with multiple branches, a regular if-else is more readable.
Spread Operator (...)
Spread expands an iterable (array, string) or object into individual elements:
const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
const combined = [...arr1, ...arr2];
console.log(combined); // [1, 2, 3, 4, 5, 6]
// Copy an array
const copy = [...arr1];
// Spread into function arguments
const nums = [10, 20, 30];
console.log(Math.max(...nums)); // 30
// Spread objects
const base = { a: 1, b: 2 };
const extended = { ...base, c: 3, b: 99 }; // b is overridden
console.log(extended); // { a: 1, b: 99, c: 3 }
typeof and instanceof
typeof "hello" // "string"
typeof 42 // "number"
typeof {} // "object"
typeof [] // "object"
// instanceof checks prototype chain
[] instanceof Array // true
[] instanceof Object // true (arrays are objects)
{} instanceof Object // true
class Dog {}
const rex = new Dog();
rex instanceof Dog // true
rex instanceof Object // true
Key Takeaways
- Use
===and!==โ never==or!= ||falls back on any falsy value;??only onnull/undefined?.lets you safely navigate nested properties&&short-circuits on the first falsy value- The spread operator
...copies/merges arrays and objects
Ready to test your knowledge?
Take a quiz on what you just learned.