Skip to content

Exercise 10 of 10 · A complete program

The Cafe Ticket

What you will make

A printed cafe receipt: the shop name across the top, three item rows whose quantity, unit price and amount all land in straight columns, a subtotal, a service charge the program works out itself, a total, and a thank-you line.

The one new idea: assembling a complete program out of parts you already know

Real software is almost never one clever idea. It is a handful of ordinary ones stacked in the order the work happens, and being able to look at a finished program and name its parts is what lets you read other people's JavaScript. In JavaScript that reading includes a decision some other languages never ask for: whether each name is one the program will change.

Go straight to the code ↓

Everything you know, in one program

Every exercise so far handed you one new idea. This one hands you none: every line in the editor is something you have already written.

That is what a finished program is — not one clever trick, but ordinary ones arranged in the order the work happens. Here is this receipt, named piece by piece, with the exercise each part came from:

  • console.log puts a line on the screen. Exercise 1.
  • const and let put names on values — exercise 2 for const, exercise 5 for let.
  • qty * price turns two numbers into an amount, and Math.floor keeps the service charge to whole rupees. Exercise 3.
  • An if decides whether the service charge applies at all, and its braces decide which lines belong to it. Exercises 4 and 6.
  • A template literal with padEnd and padStart lands the columns in a straight line. Exercise 7.
  • An array and a for...of loop print the two notes at the bottom. Exercise 8.
  • subtotal = subtotal + cost collects the order one item at a time, the same shape as the total = total + mm that collected a week of rainfall. Exercise 9.

Seven ideas, none of them new, all in one receipt.

Which names change, and which never do

JavaScript asks you to say, for every name you declare, whether it will ever point at something else. Read that decision off the page:

  • subtotal, item, qty, price and cost are all let: the subtotal grows once per item, and each block writes the next item over the last.
  • service is let for a quieter reason. It is set to 0 first, then replaced if the bill is big enough. A const declared inside the braces of the if would belong to those braces alone and be gone by the closing one.
  • total and notes are const, each settled once and never touched again.

Reach for const first. Change it to let only when the program shows you it has to.

A worked example

A stationery stall rather than a cafe, so the receipt in the editor stays yours to finish:

JavaScript
let total = 0;

let item = "Notebook";
let cost = 45;
total = total + cost;
console.log(`${item.padEnd(10)}${String(cost).padStart(5)}`);

item = "Pen";
cost = 12;
total = total + cost;
console.log(`${item.padEnd(10)}${String(cost).padStart(5)}`);

const tenth = Math.floor(total / 10);

console.log("---------------");
console.log(`Charge${String(tenth).padStart(9)}`);
console.log(`TOTAL${String(total + tenth).padStart(10)}`);
Output
Notebook     45
Pen          12
---------------
Charge        5
TOTAL        62

Nothing there is typed in but the two items and their prices: the total collects itself, and Math.floor turns a tenth of it, 5.7, into a whole 5. Change the 45 to 55 and the charge and the total both move, with nobody retyping either.

Your turn

Press Run before changing anything. Most of the receipt is already right: the header, the first two rows, the service charge, the notes at the bottom.

Two lines are marked. Both already run: they are wrong, not missing.

  1. The cake's row still glues its four values together with plus signs, so the numbers land nowhere near the columns above. Rewrite it as a template literal matching the two finished rows; the widths you need are sitting on them.
  2. total is 0, so the bottom of the receipt disagrees with the rest of it. Work it out from the two values the program already holds: the amount for the items, and the charge added on top.

Then change something — two slices of cake, a different price for the chai — and run it again. The row, the subtotal and the total all move together, and the service charge follows whenever the subtotal crosses into a new ten. That is a receipt worked out, not typed.

If something goes wrong

The likeliest slip is the total, and it announces itself: the TOTAL line still shows 0, or disagrees with the two numbers above it. Check that both names to the right of the = are spelled as they are further up, and that the line still sits below the if. JavaScript works down the page, so a total written just above the if adds a service charge that is still 0, and the receipt ends at 140.

If the cake row prints dollar signs and braces at you word for word, its quotes are still the ordinary kind and the row wants backticks. If it prints but sits out of line, count its widths against the rows above rather than guessing. And if the program stops on TypeError: Assignment to constant variable, something declared with const is being asked to change.

Nothing here can break. Change the order, run it again, and read your own receipt.

Write your code

Runs in your browser. Press Run (or Ctrl/Cmd+Enter) and the output is checked for you.

Ctrl/Cmd+Enter to run

Press Esc then Tab to move keyboard focus out of the code editor.

Ready
Output will appear here after you run your code.

The runtime is starting in the background. You can type now — it will be ready before you are.

The answer appears here once you have run your code at least once.

Things that often go wrong here

Typing the final total in by hand
The number is right this minute and wrong the moment anything changes. Order two slices of cake instead of one and the cake's row, the subtotal and the service charge update themselves, while a typed total sits underneath contradicting them. A total is worked out from the values above it, never copied off the screen.
Leaving the cake row in double quotes
Nothing breaks and nothing complains. The row simply prints the dollar signs, the braces and the names back at you as ordinary characters, because only backtick quotes treat them as instructions to fill something in.
Writing the total as cost plus service
cost holds the amount for the last item only, because each block writes its own figure over the top of the one before, so the receipt ends at 69 instead of 154. The name that has been collecting the whole order is subtotal.
Giving the cake row different widths from the rows above it
Those rows line up only because each of them gives the item twelve characters, the quantity three, the unit price five and the amount six. Change one of those numbers on one row and that row alone drifts out of column while the others stay where they are.
Declaring the service charge with const inside the if
A name declared inside braces belongs to those braces alone, so it is gone again by the closing one. Delete the let line above the if and the program stops at the total line with ReferenceError: service is not defined. Keep it and nothing complains at all: the receipt quietly shows a service charge of 0 and a total of 140. A value needed after the if is declared once before it, and only changed inside.

Want a blank editor instead? Open the JavaScript playground.