Skip to content

Exercise 7 of 10 · Strings and formatting

The Scoreboard

What you will make

A game scoreboard where every name, score and bar lands in the same column, with each row built as one piece of text that has the values sitting inside it.

The one new idea: template literals build text with values inside it

Receipts, timetables and printed reports are all text with values dropped into fixed-width columns. Template literals are how JavaScript writes that, and reaching for one instead of gluing pieces together with a plus sign is the habit that stops a sum like 5 plus 2 quietly coming out as 52 behind your back.

Go straight to the code ↓

Text written between backticks

Everything you have printed so far was a fixed piece of text in double quotes, or several values handed to console.log and separated by commas. Commas work, but they always give exactly one space between the pieces — never the five that would drop a number under a heading. As soon as you care what a line looks like rather than what it says, that is not enough.

A template literal is a single piece of text with the values already inside it. You write it between backtick quotes — on a US or UK keyboard, the key above Tab and left of the 1, not the apostrophe — and anywhere inside you write a dollar sign, an opening brace, a name, and a closing brace. JavaScript swaps each of those for whatever the name holds.

JavaScript
const player = "Ana";
const score = 12;
console.log(`${player} scored ${score}`);
console.log("${player} scored ${score}");
Output
Ana scored 12
${player} scored ${score}

Those two lines differ only in their quotes. Backticks are what bring the braces to life; in double quotes there is no error, just the names printed back at you.

The braces are not limited to a bare name. Anything that works out to a value can sit between them — a sum, or a name with something done to it — and the rest of this lesson puts both there.

The plus sign works, and that is the trap

JavaScript has another way to build that line, and it will not stop you:

JavaScript
const hits = 5;
const bonus = 2;
console.log("Points: " + hits + bonus);
console.log(`Points: ${hits + bonus}`);
Output
Points: 52
Points: 7

Read those outputs twice. A plus sign between text and a number turns the number into text and joins it on the end. By then the left-hand side is text too, so the second plus joins rather than adds: five and two become fifty-two, with no error and no warning.

Inside a template literal the braces decide where each value goes, which leaves + free to mean what it always meant. Backticks are worth the habit now, not after a scoreboard has lied to you.

padEnd, padStart, and the String around the score

A fixed width is the whole trick behind a column.

  • player.padEnd(7) gives the name seven characters, adding spaces on the end until it fills them, so whatever follows begins at the eighth character on every row.
  • String(score).padStart(3) gives the score three characters, adding spaces at the start, so one-digit and two-digit scores finish in the same place.

String(score) is not ceremony. Padding is something text can do, and score.padStart(3) stops the program with TypeError: score.padStart is not a function. A template literal does turn values into text, but only as it drops them in — the padding is asked for first, so the number has to be text already.

A worked example

A bird tally rather than a scoreboard, so the answer stays yours to write:

JavaScript
let bird = "Owl";
let seen = 3;
console.log("[" + bird + "][" + seen + "]");
console.log(`[${bird.padEnd(6)}][${String(seen).padStart(4)}]`);

bird = "Heron";
seen = 14;
console.log(`[${bird.padEnd(6)}][${String(seen).padStart(4)}]`);
Output
[Owl][3]
[Owl   ][   3]
[Heron ][  14]

The square brackets are there only to make the padding visible. The glued row hugs its values; the two below give every name six characters and every count four, so both closing brackets land in the same column, and so do both numbers.

Your turn

The editor holds a scoreboard with three players. Each gets a name, a score, and bar = "#".repeat(score), which makes one copy of # per point. Those three are let rather than const because each player writes their own values over them.

Press Run first. Ana and Ben come out as tidy rows; Cleo's row is ragged, because her line is still glued together with plus signs and nothing gives her values a fixed width: console.log(player + " " + score + " " + bar);

Rewrite that one line as a template literal so her row matches the two above it. The widths you need are already on screen, and nothing else needs changing.

Then set her score to 11 and run it again: the bar grows, the row stays in column. Put the 5 back afterwards.

If something goes wrong

The likeliest slip is the quotes. If the row prints dollar signs and braces at you word for word, it is still in double quotes and wants backticks — on a US or UK keyboard, the key left of the 1. Nothing has broken.

If the program stops on a TypeError saying something is not a function, the padding was asked of a number rather than of text, so the score needs wrapping in String(...).

If the row prints in the wrong place, either padEnd and padStart are the wrong way round, or the ordinary space between the last two insertions went missing.

Nothing here can break. Change a number, press Run, and read your own board.

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

Leaving the row in double quotes
Nothing breaks and nothing complains. The row simply prints the dollar signs, the braces and the variable names at you word for word, because in ordinary quotes those are just characters. Only a backtick quote treats them as instructions to fill something in.
Building the row with plus signs instead
JavaScript does not stop you. A plus sign between text and a number quietly turns the number into text and joins it on the end, and with no padding each value takes only the room it needs, so the columns land wherever the values happen to end. Worse, once the left-hand side is text, the next plus joins rather than adds, so 5 and 2 come out as 52 instead of 7.
Asking a number to pad itself
padEnd and padStart are things a piece of text can do, and a score is a number, so the program stops with TypeError: score.padStart is not a function. Wrapping it in String first turns the number into text, and text can be padded.
Swapping padEnd and padStart round
The row still prints, but backwards: the name is pushed to the right of its seven characters and the score sits at the left of its three, so the two run together as Cleo5. The left edge of the board goes ragged, and the 5 no longer lines up with the 12 and the 8 above it.

Want a blank editor instead? Open the JavaScript playground.