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 returns NaN or Infinity instead of throwing errors.

Navigation: ← 1.18 Overview · 1.18.b — Comparison Operators →


1. The basic five

OperatorNameExampleResult
+Addition10 + 313
-Subtraction10 - 37
*Multiplication10 * 330
/Division10 / 33.3333…
%Remainder (modulus)10 % 31
// 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:

FormNameReturnsSide effect
++xPre-incrementThe new valuex = x + 1 first
x++Post-incrementThe old valuex = x + 1 after
--xPre-decrementThe new valuex = x - 1 first
x--Post-decrementThe old valuex = 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)OperatorsAssociativity
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

  1. Five basic operators (+, -, *, /, %) plus ** for exponentiation cover all arithmetic.
  2. ++/-- have pre and post forms — the difference is which value is returned, not the final result.
  3. Operator precedence follows math rules; use parentheses when in doubt.
  4. + with strings triggers concatenation, not addition — a major source of bugs.
  5. NaN is not equal to itself; use Number.isNaN() to detect it.
  6. Infinity arises from division by zero; NaN arises from invalid math.
  7. Floating-point arithmetic can produce tiny rounding errors — never compare decimals with ===.

Explain-It Challenge

Explain without notes:

  1. What is the result of "5" + 3 and why? What about "5" - 3?
  2. What is the difference between x++ and ++x?
  3. Why does 0.1 + 0.2 !== 0.3 in JavaScript?
  4. How do you reliably check if a value is NaN?
  5. What does 10 % 3 return, and give one practical use of the % operator.

Navigation: ← 1.18 Overview · 1.18.b — Comparison Operators →