Episode 1 — Fundamentals / 1.18 — Operators and Type System
1.18.a — Arithmetic Operators
In one sentence: JavaScript's arithmetic operators (
+,-,*,/,%,**) perform math on numbers, but the+operator doubles as a string concatenator, and invalid math silently returnsNaNorInfinityinstead of throwing errors.
Navigation: ← 1.18 Overview · 1.18.b — Comparison Operators →
1. The basic five
| Operator | Name | Example | Result |
|---|---|---|---|
+ | Addition | 10 + 3 | 13 |
- | Subtraction | 10 - 3 | 7 |
* | Multiplication | 10 * 3 | 30 |
/ | Division | 10 / 3 | 3.3333… |
% | Remainder (modulus) | 10 % 3 | 1 |
// Quick demo
console.log(7 + 2); // 9
console.log(7 - 2); // 5
console.log(7 * 2); // 14
console.log(7 / 2); // 3.5 (JS has no integer division)
console.log(7 % 2); // 1 (remainder after dividing 7 by 2)
The remainder operator %
% returns what is left over after integer division. It is extremely useful for:
// Even/odd check
const isEven = (n) => n % 2 === 0;
console.log(isEven(4)); // true
console.log(isEven(7)); // false
// Cycling through indices (wrap around)
const colors = ["red", "green", "blue"];
for (let i = 0; i < 9; i++) {
console.log(colors[i % colors.length]);
// red, green, blue, red, green, blue, red, green, blue
}
// Clock arithmetic
const totalMinutes = 135;
const hours = Math.floor(totalMinutes / 60); // 2
const minutes = totalMinutes % 60; // 15
console.log(`${hours}h ${minutes}m`); // "2h 15m"
2. Exponentiation operator **
Introduced in ES2016, ** raises the left operand to the power of the right.
console.log(2 ** 3); // 8 (2 cubed)
console.log(5 ** 2); // 25 (5 squared)
console.log(9 ** 0.5); // 3 (square root)
console.log(2 ** -1); // 0.5 (1/2)
// Equivalent to Math.pow()
console.log(Math.pow(2, 3)); // 8
Right-associative: 2 ** 3 ** 2 means 2 ** (3 ** 2) = 2 ** 9 = 512, not (2 ** 3) ** 2 = 64.
console.log(2 ** 3 ** 2); // 512
3. Increment ++ and decrement --
These operators add or subtract 1 and come in two flavors:
| Form | Name | Returns | Side effect |
|---|---|---|---|
++x | Pre-increment | The new value | x = x + 1 first |
x++ | Post-increment | The old value | x = x + 1 after |
--x | Pre-decrement | The new value | x = x - 1 first |
x-- | Post-decrement | The old value | x = x - 1 after |
let a = 5;
console.log(++a); // 6 (increments first, then returns 6)
console.log(a); // 6
let b = 5;
console.log(b++); // 5 (returns 5 first, then increments)
console.log(b); // 6
Practical difference in loops
// Both loops run the same number of times,
// but the returned value mid-expression differs.
let i = 0;
while (i < 3) {
console.log(i++); // prints 0, 1, 2 (post: logs old value)
}
let j = 0;
while (j < 3) {
console.log(++j); // prints 1, 2, 3 (pre: logs new value)
}
Best practice: Avoid using ++/-- inside larger expressions where the pre/post distinction creates confusion. Use them on their own line or in for loop update clauses.
4. Operator precedence (BODMAS / PEMDAS in JS)
JavaScript evaluates operators in a defined order. Higher precedence binds first.
| Precedence (high → low) | Operators | Associativity |
|---|---|---|
| 1 — Grouping | ( ) | n/a |
| 2 — Exponentiation | ** | Right |
| 3 — Unary | +x, -x, ++, -- | Right |
| 4 — Multiplicative | *, /, % | Left |
| 5 — Additive | +, - | Left |
| 6 — Comparison | <, >, <=, >= | Left |
| 7 — Equality | ==, !=, ===, !== | Left |
| 8 — Logical AND | && | Left |
| 9 — Logical OR | ` | |
| 10 — Assignment | =, +=, etc. | Right |
// Without parentheses
console.log(2 + 3 * 4); // 14 (not 20)
console.log(2 + 3 * 4 ** 2); // 50 → 4**2=16, 3*16=48, 2+48=50
// Parentheses override
console.log((2 + 3) * 4); // 20
Rule of thumb: When in doubt, use parentheses. They cost nothing and prevent bugs.
5. String concatenation with + (type coercion preview)
The + operator is overloaded: if either operand is a string, JavaScript converts the other to a string and concatenates.
console.log("Hello" + " " + "World"); // "Hello World"
console.log("Age: " + 25); // "Age: 25" (25 → "25")
console.log(5 + "3"); // "53" (5 → "5")
console.log("5" + 3); // "53"
console.log(1 + 2 + "3"); // "33" (1+2=3, then 3+"3"="33")
console.log("1" + 2 + 3); // "123" ("1"+2="12", "12"+3="123")
Key insight: Evaluation is left-to-right. The moment a string appears, everything after concatenates.
The other arithmetic operators (-, *, /, %) do not concatenate — they convert strings to numbers:
console.log("10" - 3); // 7 (number)
console.log("10" * 2); // 20 (number)
console.log("10" / 5); // 2 (number)
console.log("10" % 3); // 1 (number)
This asymmetry is covered in depth in 1.18.g — Type Coercion.
6. NaN — Not a Number
When arithmetic cannot produce a meaningful number, JavaScript returns NaN instead of throwing an error.
console.log(0 / 0); // NaN
console.log("hello" * 2); // NaN
console.log(undefined + 1); // NaN
console.log(Math.sqrt(-1)); // NaN
NaN is not equal to itself
console.log(NaN === NaN); // false (!)
console.log(NaN == NaN); // false
How to check for NaN
// Modern (preferred)
console.log(Number.isNaN(NaN)); // true
console.log(Number.isNaN("hello")); // false (does NOT coerce)
// Legacy (avoid — coerces first)
console.log(isNaN("hello")); // true (converts "hello" → NaN first)
console.log(isNaN("123")); // false
// Object.is
console.log(Object.is(NaN, NaN)); // true
typeof NaN is "number" — one of JavaScript's most confusing facts.
console.log(typeof NaN); // "number"
7. Infinity and -Infinity
console.log(1 / 0); // Infinity
console.log(-1 / 0); // -Infinity
console.log(Infinity + 1); // Infinity
console.log(Infinity - Infinity); // NaN
console.log(Infinity * 0); // NaN
Checking for finite values
console.log(isFinite(42)); // true
console.log(isFinite(Infinity)); // false
console.log(isFinite(NaN)); // false
// Number.isFinite (no coercion — preferred)
console.log(Number.isFinite("42")); // false (string, not coerced)
console.log(Number.isFinite(42)); // true
Number.MAX_SAFE_INTEGER and overflow
console.log(Number.MAX_SAFE_INTEGER); // 9007199254740991 (2^53 - 1)
console.log(Number.MAX_SAFE_INTEGER + 1 === Number.MAX_SAFE_INTEGER + 2); // true (!!)
// For very large integers, use BigInt (beyond this lesson)
8. Practical examples with real calculations
Shopping cart total
const prices = [9.99, 24.50, 3.75, 14.99];
let total = 0;
for (let i = 0; i < prices.length; i++) {
total += prices[i];
}
const tax = total * 0.08;
const grandTotal = total + tax;
console.log(`Subtotal: $${total.toFixed(2)}`); // "Subtotal: $53.23"
console.log(`Tax (8%): $${tax.toFixed(2)}`); // "Tax (8%): $4.26"
console.log(`Total: $${grandTotal.toFixed(2)}`); // "Total: $57.49"
Temperature conversion
function celsiusToFahrenheit(c) {
return (c * 9 / 5) + 32;
}
function fahrenheitToCelsius(f) {
return (f - 32) * 5 / 9;
}
console.log(celsiusToFahrenheit(0)); // 32
console.log(celsiusToFahrenheit(100)); // 212
console.log(fahrenheitToCelsius(72)); // 22.222...
Leap year check
function isLeapYear(year) {
return (year % 4 === 0 && year % 100 !== 0) || (year % 400 === 0);
}
console.log(isLeapYear(2024)); // true
console.log(isLeapYear(1900)); // false
console.log(isLeapYear(2000)); // true
Floating-point precision warning
console.log(0.1 + 0.2); // 0.30000000000000004 (!)
console.log(0.1 + 0.2 === 0.3); // false
// Fix: compare with a tolerance
const EPSILON = Number.EPSILON;
console.log(Math.abs((0.1 + 0.2) - 0.3) < EPSILON); // true
// Or work in smallest unit (cents instead of dollars)
const priceInCents = 199 + 50; // 249 (no floating-point issue)
Key takeaways
- Five basic operators (
+,-,*,/,%) plus**for exponentiation cover all arithmetic. ++/--have pre and post forms — the difference is which value is returned, not the final result.- Operator precedence follows math rules; use parentheses when in doubt.
+with strings triggers concatenation, not addition — a major source of bugs.NaNis not equal to itself; useNumber.isNaN()to detect it.Infinityarises from division by zero;NaNarises from invalid math.- Floating-point arithmetic can produce tiny rounding errors — never compare decimals with
===.
Explain-It Challenge
Explain without notes:
- What is the result of
"5" + 3and why? What about"5" - 3? - What is the difference between
x++and++x? - Why does
0.1 + 0.2 !== 0.3in JavaScript? - How do you reliably check if a value is
NaN? - What does
10 % 3return, and give one practical use of the%operator.
Navigation: ← 1.18 Overview · 1.18.b — Comparison Operators →