Warm-up · Activity 1 of 7
Warm-up: what does this print?
console.log(7 / 2);// B2.2 · ~30 min · Beginner
After this lesson you can calculate with every arithmetic operator, round numbers the way you mean to, and deal with NaN, Infinity and numbers hidden inside text.
You will be able to
Warm-up · Activity 1 of 7
console.log(7 / 2);Predict · Activity 2 of 7
console.log(0.1 + 0.2);Practice · Activity 3 of 7
console.log(17 ____ 5);Practice · Activity 4 of 7
Practice · Activity 5 of 7
const price = (19.999).toFixed(2);
console.log(price + 1);Brain teaser · Activity 6 of 7
console.log((1.005).toFixed(2));Apply · Activity 7 of 7
Check your work against this list
Read the worked example, then write the exercises. Your code runs in your browser or on your computer and is never uploaded.
Worked example
Three friends split a bill of 87.40 euros. The exact share has a long tail of digits, so the program formats it with toFixed, rounds it up with Math.ceil, and uses % to seat ten guests at tables of four. It ends with two numbers read from text and a calculation that breaks. Run it, then change people to 4.
main.js
// Splitting a restaurant bill between friends.
const bill = 87.4;
const people = 3;
const share = bill / people;
console.log("exact share:", share);
console.log("rounded:", share.toFixed(2), typeof share.toFixed(2));
console.log("each pays, whole euros:", Math.ceil(share));
console.log("tip at 10%:", Math.round(bill * 0.1));
console.log("tables of 4 for 10 guests:", Math.ceil(10 / 4), "with", 10 % 4, "at the last");
console.log("from text:", Number.parseFloat("12.5%"), Number.parseInt("3 guests", 10));
console.log("broken:", 0 / 0, Number.isNaN(0 / 0), 1 / 0);
Run it with
node main.jsOutput
exact share: 29.133333333333336
rounded: 29.13 string
each pays, whole euros: 30
tip at 10%: 9
tables of 4 for 10 guests: 3 with 2 at the last
from text: 12.5 3
broken: NaN true InfinityTab indents and Shift+Tab outdents. To leave the editor with the keyboard, press Esc, then Tab.
The first run downloads the JavaScript runner (up to 0.1 MB) and keeps it cached. Your code runs in your browser’s own engine and stays on your device.
Exercise 1 of 2
Three winners share a prize of 100 euros. Print three lines: Each: 33.33 (the exact share with two decimals), Round up: 34 (the share rounded up to whole euros) and Remainder: 1 (the euros left over if each gets a whole number of euros). Calculate every value from prize and winners.
Tab indents and Shift+Tab outdents. To leave the editor with the keyboard, press Esc, then Tab.
The first run downloads the JavaScript runner (up to 0.1 MB) and keeps it cached. Your code runs in your browser’s own engine and stays on your device.
(prize / winners).toFixed(2) gives "33.33". The brackets make the division happen first.
Math.ceil always rounds up, so 33.33… becomes 34.
The remainder after dividing is prize % winners.
One way to solve it. Yours can look different and still pass the checks.
const prize = 100;
const winners = 3;
console.log("Each:", (prize / winners).toFixed(2));
console.log("Round up:", Math.ceil(prize / winners));
console.log("Remainder:", prize % winners);
Install ECMAScript 2026 or newer. Save these files in one folder, open a terminal in that folder, and run the commands below.
main.js
const prize = 100;
const winners = 3;
// Print three lines:
// Each: 33.33
// Round up: 34
// Remainder: 1
console.log("Each:", prize / winners);
main.test.js
import {test} from 'node:test';
import assert from 'node:assert/strict';
import {runMain} from './learnrun.js';
const lines = async () => (await runMain()).trimEnd().split('\n');
test('prints the share with two decimals', async () => {
const got = await lines();
assert.equal(got[0], 'Each: 33.33', `the first line is ${JSON.stringify(got[0])}, expected "Each: 33.33"`);
});
test('prints the share rounded up', async () => {
const got = await lines();
assert.equal(got[1], 'Round up: 34', `the second line is ${JSON.stringify(got[1])}, expected "Round up: 34"`);
});
test('prints the remainder', async () => {
const got = await lines();
assert.equal(got[2], 'Remainder: 1', `the third line is ${JSON.stringify(got[2])}, expected "Remainder: 1"`);
});
package.json
{
"type": "module"
}
package.json tells Node.js that the .js files are modules; keep it in the folder.
Run the program:
node main.jsRun the checks (needs learnrun.js in the same folder):
node --testDownload learnrun.jsExercise 2 of 2
Three labels were read as text: "12.5 kg", "7 items" and "abc". Number() turns all three into NaN. Print weight: 12.5 with Number.parseFloat, count: 7 with Number.parseInt (base 10), and invalid: true by checking with Number.isNaN whether parseFloat of "abc" failed.
Tab indents and Shift+Tab outdents. To leave the editor with the keyboard, press Esc, then Tab.
The first run downloads the JavaScript runner (up to 0.1 MB) and keeps it cached. Your code runs in your browser’s own engine and stays on your device.
Number.parseFloat(weightText) reads 12.5 and stops at the space before kg.
Number.parseInt(countText, 10) reads the whole number 7.
Number.parseFloat("abc") is NaN, and Number.isNaN(NaN) is true.
One way to solve it. Yours can look different and still pass the checks.
const weightText = "12.5 kg";
const countText = "7 items";
const badText = "abc";
console.log("weight:", Number.parseFloat(weightText));
console.log("count:", Number.parseInt(countText, 10));
console.log("invalid:", Number.isNaN(Number.parseFloat(badText)));
Install ECMAScript 2026 or newer. Save these files in one folder, open a terminal in that folder, and run the commands below.
main.js
const weightText = "12.5 kg";
const countText = "7 items";
const badText = "abc";
console.log("weight:", Number(weightText));
console.log("count:", Number(countText));
console.log("invalid:", Number(badText));
main.test.js
import {test} from 'node:test';
import assert from 'node:assert/strict';
import {runMain} from './learnrun.js';
const lines = async () => (await runMain()).trimEnd().split('\n');
test('reads the weight', async () => {
const got = await lines();
assert.equal(got[0], 'weight: 12.5', `the first line is ${JSON.stringify(got[0])}, expected "weight: 12.5"`);
});
test('reads the count', async () => {
const got = await lines();
assert.equal(got[1], 'count: 7', `the second line is ${JSON.stringify(got[1])}, expected "count: 7"`);
});
test('reports the invalid label', async () => {
const got = await lines();
assert.equal(got[2], 'invalid: true', `the third line is ${JSON.stringify(got[2])}, expected "invalid: true"`);
});
package.json
{
"type": "module"
}
package.json tells Node.js that the .js files are modules; keep it in the folder.
Run the program:
node main.jsRun the checks (needs learnrun.js in the same folder):
node --testDownload learnrun.jsconst price = "4.5";
console.log(price.toFixed(2));
What Node.js prints
TypeError: price.toFixed is not a functionWhy, and the fix
toFixed is a number method, and "4.5" in quotes is a string, which has no toFixed. This often happens with values from a form or with a value that already went through toFixed once. Convert first: Number(price).toFixed(2) prints 4.50.
console.log(5.toFixed(2));
What Node.js prints
SyntaxError: Invalid or unexpected tokenWhy, and the fix
JavaScript reads the dot after 5 as the start of the decimals, so 5.toFixed is a number with letters in its decimals, which cannot be read. Nothing in the file runs. Put the number in brackets, (5).toFixed(2), or store it in a variable first: const n = 5; n.toFixed(2). Both print 5.00.
const share = 100 / 3;
console.log(share.toFixed(101));
What Node.js prints
RangeError: toFixed() digits argument must be between 0 and 100Why, and the fix
toFixed accepts 0 to 100 digits after the point; anything else stops the program with a RangeError, the error for a value outside its allowed range. Two digits are usually what you want for money. Asking for many digits does not make the number more exact either: it only shows more of the binary storage error.
JavaScript in the browser: your browser’s own engine, in a sandboxed worker. Syntax errors are located with acorn 8.18.0, MIT. Licence and source
5 questions, no hints. Score 80% or more to complete the lesson.
Finish every activity above to unlock the exit ticket.