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.logputs a line on the screen. Exercise 1.constandletput names on values — exercise 2 forconst, exercise 5 forlet.qty * priceturns two numbers into an amount, andMath.floorkeeps the service charge to whole rupees. Exercise 3.- An
ifdecides whether the service charge applies at all, and its braces decide which lines belong to it. Exercises 4 and 6. - A template literal with
padEndandpadStartlands the columns in a straight line. Exercise 7. - An array and a
for...ofloop print the two notes at the bottom. Exercise 8. subtotal = subtotal + costcollects the order one item at a time, the same shape as thetotal = total + mmthat 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,priceandcostare alllet: the subtotal grows once per item, and each block writes the next item over the last.serviceisletfor a quieter reason. It is set to0first, then replaced if the bill is big enough. Aconstdeclared inside the braces of theifwould belong to those braces alone and be gone by the closing one.totalandnotesareconst, 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:
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)}`);Notebook 45
Pen 12
---------------
Charge 5
TOTAL 62Nothing 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.
- 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.
totalis0, 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.
Press Esc then Tab to move keyboard focus out of the code editor.
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.