EduFlow
JavaScript Fundamentals
0%

Section 1 · First Steps

Numbers, Operators and Comparisons

17 min4 min readCode playground

Lesson at a glance

Do arithmetic with JavaScript numbers, avoid floating-point surprises by storing money in whole cents, and compare values safely with === instead of ==.

  1. 1Arithmetic, the usual way
  2. 2Why 0.1 + 0.2 is not 0.3
  3. 3When + joins instead of adds
  4. 4Comparing values

No video here — just the real thing: a written lesson, runnable examples, a quiz and practice.

Ask JavaScript to add up a coffee, a lunch and a bus ticket, and it gets the answer slightly wrong:

JavaScript
console.log(4.1 + 12.2 + 2.7);

You expected 19 and got 18.999999999999996. This is not a JavaScript bug; nearly every programming language does the same thing. Once you know why, you can design Pocket so it never bites you.

Arithmetic, the usual way

The arithmetic operators work as you would hope, with the usual precedence: *, / and % happen before + and -, and parentheses override everything.

JavaScript
console.log(2 + 3 * 4);    // multiplication first
console.log((2 + 3) * 4);  // parentheses first
console.log(17 % 5);       // remainder after dividing 17 by 5
console.log(2 ** 10);      // 2 to the power of 10

% (remainder) is more useful than it looks: n % 2 === 0 tells you whether a number is even, and minutes % 60 gives the leftover minutes after whole hours.

When you update a variable from its own value, there are shorthands. total += 450 means total = total + 450, and the same pattern works for -=, *= and /=. count++ adds one, which you will see in loops.

Why 0.1 + 0.2 is not 0.3

JavaScript has a single number type, used for both whole numbers and decimals. Under the hood every number is stored in binary, in 64 bits, following a standard called IEEE 754. Whole numbers fit perfectly. Many decimals do not: in binary, 0.1 is a fraction that repeats forever, like 1/3 in decimal (0.3333…). The computer has to cut it off somewhere, so it stores the nearest value it can. Add a few of these near-misses and the error becomes visible.

JavaScript
console.log(0.1 + 0.2);
console.log(0.1 + 0.2 === 0.3);
console.log(4.1 * 100);

The error is tiny, about one part in ten quadrillion, so for measuring distances or drawing on screen it never matters. For money it does. A total that should be 19 but is stored as 18.999999999999996 fails an equality check, rounds the wrong way on a receipt, and drifts further every time you add another expense. Rounding the display hides the symptom while the stored number stays wrong.

For money, the fix is simple and it is what payment companies do: store amounts as whole cents. Whole numbers are exact up to Number.MAX_SAFE_INTEGER, about 9 quadrillion, which is plenty for an expense tracker.

JavaScript
const coffee = 410;   // $4.10 in cents
const lunch = 1220;
const bus = 270;
const total = coffee + lunch + bus;
console.log(total);         // exact
console.log(total / 100);   // convert to dollars only when you display it

From this lesson on, every amount in Pocket is stored in cents. When an amount arrives in dollars, such as 4.1, convert it once with Math.round(4.1 * 100). The Math.round matters, because 4.1 * 100 is 409.99999999999994, and rounding snaps it to 410.

When + joins instead of adds

Values typed into a web page always arrive as strings, even when they look like numbers. And + has two jobs: adding numbers and joining strings. If either side is a string, it joins.

JavaScript
const typed = "5";
console.log(typed + 3);          // joins: "53"
console.log(typed - 3);          // only maths makes sense, so 2
console.log(Number(typed) + 3);  // convert first: 8
console.log(Number("12abc"));    // not a number: NaN

The other operators (-, *, /) only do maths, so they convert strings to numbers silently, which makes the bug harder to spot: the subtraction works and the addition does not. Convert input explicitly with Number() as soon as you receive it.

When a conversion fails you get NaN, “not a number”, which is confusingly of type number. NaN spreads: any maths with it gives NaN. Test for it with Number.isNaN(value), because NaN === NaN is false.

Its cousin is Infinity. Dividing by zero does not crash a JavaScript program the way it does a calculator: 5 / 0 is Infinity and -5 / 0 is -Infinity. That sounds harmless until Pocket computes “average spend per day” on the first of the month with zero days recorded. Neither NaN nor Infinity throws an error, so your program keeps running and shows nonsense. The defence is the same for both: check your inputs before you calculate.

Comparing values

Comparison operators produce a boolean: >, <, >=, <=, and the two kinds of equality.

=== (strict equality) is true only when both values have the same type and the same value. == (loose equality) first converts the two sides to a common type, following rules that surprise even experienced developers:

Expression == ===
"5" and 5 true false
"" and 0 true false
null and undefined true false
"0" and false true false

Use === and !== everywhere. If the types might differ, convert explicitly first, then compare. Your code then says exactly what it means, and nobody has to remember a conversion table.

JavaScript
const budgetCents = 2500;
const spentCents = 2200;
const isOverBudget = spentCents > budgetCents;
console.log(isOverBudget, typeof isOverBudget);
console.log(spentCents === 2200, "2200" === 2200);

With exact amounts and safe comparisons, the next step is to show them nicely: strings, and how to build readable text like “Lunch: $12.20”.

Key takeaways

  • JavaScript has one number type for whole and decimal numbers, and decimals are stored in binary, so 0.1 + 0.2 is not exactly 0.3.
  • Store money as whole cents (integers) and convert to dollars only for display; whole-number arithmetic is exact.
  • + with a string joins text instead of adding, so convert input with Number() before doing maths.
  • Always compare with === and !==; == converts types first and gives answers like \"\" == 0 being true.

Further reading

Check your understanding

4 questions

Question 1 of 4

A user types 5 into a text box, so your code receives the string "5". What is "5" + 3?

Question 2 of 4

Pocket stores a coffee as 4.1 dollars and a lunch as 12.2. Why is storing 410 and 1220 cents a better design?

Question 3 of 4

Which comparison is true?

Question 4 of 4

What does let n = 4; n += 2; n *= 3; leave in n?

Practice

Code playground

Total in cents, exactly

The starter adds three dollar amounts and a typed string, and gets a mess. Fix totalCents so it is the exact total in whole cents of all four amounts (convert each one to cents with Math.round(amount * 100), and turn typedAmount into a number first). Then declare isOverBudget, a boolean that is true when totalCents is greater than budgetCents, and leftCents, the budget minus the total.

// Three expenses, still in dollars
const coffee = 4.1;
const lunch = 12.2;
const bus = 2.7;
// A fourth amount, typed into a text box, so it arrived as a string
const typedAmount = "3";

const budgetCents = 2500;

// Fix this: it should be the exact total in whole cents
const totalCents = coffee + lunch + bus + typedAmount;

// Declare isOverBudget and leftCents below
Loading the editor…

Ctrl/⌘ + Enter to run · Runs in a sandbox in your browser. Nothing leaves your device.

Console

(no output)

Checks

  • totalCents is a number, not a string
  • totalCents is exactly 2200
  • isOverBudget is the boolean false
  • leftCents is 300