Lesson 8 of 28
Numbers and Maths
One number type, the remainder operator you will use more than you expect, and why 0.1 + 0.2 is not 0.3 — with the fixes that keep money correct.
Prices, scores, durations, page counts — sooner or later everything becomes a number. JavaScript makes numbers easier than most languages in one way and stranger in another, and it is worth knowing both halves early.
One type for everything
Many languages make you choose between whole numbers and decimals. JavaScript
does not. There is a single number type, and it holds both.
const lessons = 5;
const rating = 4.5;
typeof lessons; // "number"
typeof rating; // "number"That is one less decision to make. The cost shows up at the end of this lesson.
The five operators
Four of them look like school maths:
10 + 3; // 13
10 - 3; // 7
10 * 3; // 30
10 / 3; // 3.3333333333333335Division always gives you a decimal when it does not divide evenly. There is no separate whole-number division.
The fifth is %, the remainder operator. It gives you what is left over after
dividing:
10 % 3; // 1 — three fits into ten three times, with 1 left over
9 % 3; // 0 — nothing left overIt looks like a curiosity until you notice how many real questions are really remainder questions. Is a number even? Divide by two and check for a leftover:
const isEven = (n) => n % 2 === 0;
isEven(4); // true
isEven(7); // falseWant to do something to every third item in a list? Check the position against three:
const position = 6;
position % 3 === 0; // true — this is a third itemWrapping a value round in a circle is the same idea. Hour 25 on a clock is
25 % 12, which is 1.
Precedence, and why brackets are kind
JavaScript follows the ordering you were taught at school: multiplication and division happen before addition and subtraction.
2 + 3 * 4; // 14, not 20You can force a different order with brackets, and you should use them freely even when they change nothing:
const price = 199;
const quantity = 3;
const shipping = 40;
const total = price * quantity + shipping; // correct, but you had to think
const clearer = (price * quantity) + shipping; // correct and obviousThe brackets cost you two characters and save the next reader a pause.
Shorthand you will read everywhere
Adding to a variable and storing the result back is so common it has its own form:
let score = 10;
score = score + 5; // the long way
score += 5; // the same thing
score -= 2;
score *= 2;Adding exactly one has an even shorter form, which you will see in loops constantly:
let count = 0;
count++; // count is now 1
count--; // back to 0The Math toolbox
Math is a built-in collection of number helpers. You do not create it; it is
just there.
Math.round(4.5); // 5 — nearest, .5 goes up
Math.round(4.4); // 4
Math.floor(4.9); // 4 — always down
Math.ceil(4.1); // 5 — always up
Math.max(3, 9, 1); // 9
Math.min(3, 9, 1); // 1Math.random() gives a decimal from 0 up to, but never reaching, 1. On its own
it is rarely what you want, so it is almost always combined with floor to
pick a whole number:
const pick = Math.floor(Math.random() * 5); // 0, 1, 2, 3 or 4Multiply to set the range, then floor to chop off the decimal.
toFixed, and a classic bug
.toFixed(2) rounds to a fixed number of decimal places, which is exactly what
prices need:
const total = 597;
total.toFixed(2); // "597.00"Look closely at those quote marks. toFixed returns a string, not a
number. Keep calculating with it and things go quietly wrong:
const price = (199.5).toFixed(2); // "199.50"
price + 1; // "199.501" — glued, not addedUse toFixed at the last possible moment, when you are about to display
something. If you need the number back, wrap it: Number(price).
Text into numbers
Anything typed into a form arrives as text, always, even when it looks like a number. Two tools convert it:
Number("42"); // 42
Number("42.5"); // 42.5
Number("42kg"); // NaN — all or nothing
parseInt("42kg"); // 42 — reads from the front and stops
parseInt("kg42"); // NaNNumber() is stricter and usually what you want. parseInt is useful when a
value has a unit stuck to it, like "16px".
Forget the conversion and + betrays you:
const typed = "10";
typed + 5; // "105" — string glue
Number(typed) + 5; // 15NaN, the not-a-number number
NaN stands for "not a number", and confusingly its type is number. It is
what you get when a calculation has no sensible numeric answer:
Number("hello"); // NaN
0 / 0; // NaNDividing a normal number by zero does not produce it, incidentally — 10 / 0
gives Infinity.
NaN has one genuinely strange property: it is not equal to anything, itself
included.
NaN === NaN; // falseSo you can never test for it with ===. Use the built-in check:
Number.isNaN(Number("hello")); // trueThe 0.1 + 0.2 surprise
Try this and the result will not be what you expect:
0.1 + 0.2; // 0.30000000000000004
0.1 + 0.2 === 0.3; // falseNothing is broken. Computers store numbers using only halves, quarters,
eighths and so on. Some fractions simply cannot be written exactly that way,
in the same way one third cannot be written exactly in decimal — you get
0.3333 and keep going forever. One tenth is one of those awkward fractions, so
0.1 is stored as something very slightly off, and the error shows up when you
add.
Two practical responses. For comparisons, round before you compare, or check that the gap is tiny rather than demanding exactness. For money, do not store rupees with decimals at all. Store paise as whole numbers, which are exact, and divide only when you display:
const priceInPaise = 19950;
const display = (priceInPaise / 100).toFixed(2); // "199.50"Try it yourself
Change the quantity, then add a line that works out the price per item rounded down.
What to remember
- One
numbertype covers whole numbers and decimals. %gives the remainder, and answers "is this even" or "is this every third"..toFixed()returns a string — convert back withNumber()before any more maths.- Form input is always text; convert with
Number()before you calculate. NaNfails every comparison, so test withNumber.isNaN().- Decimals are stored approximately. Count money in paise and format at the end.
Check yourself
4 questions · pass 3/4 to unlock Making Decisions
1.Which expression checks whether a number is even?
2.What is the value of
(199.5).toFixed(2) + 1?3.Which statement about
NaNis correct?4.What is the safest way to handle money in JavaScript?
4 left to answer