Strings and text processing · Lesson 37 of 77 · concept

Building text out of values

About 45 minutes.

By the end of this lesson you can

  • Build a string from fixed wording and changing values using a template literal and ${}.
  • Write text that spans several lines without gluing newline characters onto the ends.
  • Say what happens to a number, a boolean, an array or an object when you drop it into ${}.
  • Choose between a template literal and + on purpose rather than by habit.
  • Put a literal backtick or a literal ${ into text that needs one.

Why gluing with + stops being good enough

Explanation

Suppose you want the line "3 x Notebook = 13.50" out of three variables. With + you write `quantity + " x " + item + " = " + total`, and now you are counting spaces inside quote marks while your eyes bounce between the fixed words and the changing values. Miss one space and you get "3 xNotebook".

It works. It is just hard to read and easy to get subtly wrong, and the mistakes are the kind you only notice in a screenshot from a user. The language grew a second way of writing strings specifically to fix this.

The backtick string

Explanation

A template literal is a string written between backticks — the ` character, usually to the left of the 1 key — instead of quote marks. On its own that changes nothing: `hello` and "hello" are the same string.

What backticks unlock is ${...}. Anywhere inside a template literal you can write a dollar sign, an opening brace, some JavaScript, and a closing brace, and the result of that JavaScript is dropped into the text at that spot. `${quantity} x ${item}` reads almost like the sentence you are trying to produce, with the changing parts marked out.

Whatever goes between the braces is an expression, which means any code that produces a value: a variable, a sum, a method call, a comparison, even another template literal. It is evaluated once, at the moment the line runs, and then it is over — a template literal produces a plain, ordinary, immutable string and hands it to you. There is no live link back to the variables.

A recipe that runs once, not a live view

A mental model

This is the point beginners most often get wrong, so make it explicit. Build a label with a template literal, then change the price variable on the next line, and the label does NOT update. It never could — the label is just a string, and strings do not change.

The template literal is a recipe that was followed once, when that line executed. If you need the label to reflect a later value, you run the recipe again (usually by putting it inside a function and calling it when you need the answer).

Text that spans lines

Explanation

A normal quoted string cannot contain a real line break — press Enter inside "..." and the program will not even parse. To get a new line you type the two characters \n, which JavaScript reads as one newline character.

Inside backticks you can simply press Enter. The line breaks you type are part of the string, exactly where you put them. That makes multi-line messages, small reports and formatted output far easier to see, because the code is laid out the way the output will be.

The catch is that the indentation of your code becomes part of the string too. If you indent the second line of a template literal to line up with your code, those spaces are in the text. Either accept it, or write the block flush against the left margin, which looks wrong in the file but produces the right output.

What ${} does to values that are not text

A common mistake

Whatever you put in ${} is converted to text first. Numbers and booleans do the obvious thing: 2 becomes "2", true becomes "true". null becomes "null" and undefined becomes "undefined" — which is how blank-looking bugs such as "Hello undefined" reach real users.

Arrays are converted by joining their items with commas and no spaces, so ${[1, 2]} gives "1,2". That is occasionally handy and often not what you meant.

Plain objects are the trap. ${{ a: 1 }} produces the famously useless "[object Object]", because that is what an object's default text form is. When you want to SEE an object, reach for JSON.stringify(value) instead — you will meet it properly in module 9.

None of this is an error, which is exactly why it bites. JavaScript will happily paste any value into your sentence; making sure the value is worth pasting is your job.

Backticks in your text, and when + is still fine

Explanation

If the text itself needs a backtick, put a backslash in front of it: \`. If it needs a literal dollar-brace that must NOT be substituted — writing documentation about template literals, for instance — escape the dollar: \${.

And + has not gone anywhere. For joining two variables with nothing in between, `a + b` is shorter and perfectly clear. The rule of thumb: the moment there is fixed wording mixed in with values, use a template literal; when you are only concatenating two pieces, use +.

There is a third form you will see occasionally, a function name written directly in front of a backtick string (a tagged template). It hands the pieces to that function to assemble, which libraries use for things such as escaping. You do not need it here — just recognise it so it does not look like a typo.

What to take away

Recap

Backticks plus ${expression} build text out of fixed wording and changing values, readably. Line breaks inside backticks are real line breaks in the string.

Everything in ${} is converted to text: objects become "[object Object]", arrays become comma-joined, undefined becomes "undefined". The result is a plain string, produced once, with no live connection to the variables it came from.

Worked examples

Every output below was produced by actually running the code in the same sandbox your exercises run in — it is not a prediction.

The same line, both ways

One output built twice — once with + and once with a template literal — so you can compare them side by side. They produce exactly the same string; the difference is entirely in how easy the code is to read and to get right.

1const item = "Notebook";2const price = 4.5;3const quantity = 3;4console.log(`${quantity} x ${item} = ${(price * quantity).toFixed(2)}`);5console.log(quantity + " x " + item + " = " + (price * quantity).toFixed(2));
  • line 4

    Three substitutions. The third holds a whole expression: multiply, then round to two decimals with toFixed, which returns a string such as "13.50".

  • line 5

    Identical result. Note how the spaces inside the quote marks have to be counted by eye — that is the part that goes wrong.

What it prints

3 x Notebook = 13.503 x Notebook = 13.50

A message that spans two lines

A line break typed inside backticks becomes a real newline character in the string. The last two lines prove it is genuinely one string containing a newline, not two strings.

1const name = "Sam";2const note = `Dear ${name},3Thank you for your order.`;4console.log(note);5console.log(note.length);6console.log(note.split("\n").length);
  • line 2

    The template literal opens here and does not close until the backtick on the next line, so the Enter you pressed is inside the string.

  • line 5

    35 characters, and the newline is one of them — a line break is a single character, not a formatting instruction.

  • line 6

    Splitting on \n gives two pieces, which confirms exactly one line break sits inside.

What it prints

Dear Sam,
Thank you for your order.352

What each kind of value turns into

Five values dropped into ${} so you can see the conversion rules once and recognise them later in a bug report. The fourth line is the one to remember.

1console.log(`${1 + 1}`);2console.log(`${true} ${null} ${undefined}`);3console.log(`${[1, 2]}`);4console.log(`${{ a: 1 }}`);5console.log(`${"already text"}`);
  • line 1

    The expression is evaluated first, then converted: the sum happens, and 2 becomes "2".

  • line 2

    null and undefined become the words "null" and "undefined". This is where "Hello undefined" comes from.

  • line 3

    An array joins its items with commas and no spaces.

  • line 4

    A plain object has no useful text form, so you get [object Object]. Use JSON.stringify when you want to see inside it.

What it prints

2true null undefined1,2[object Object]already text

Check yourself

Not scored, not stored. Getting one wrong is the useful part.

Both lines contain an expression inside the braces, not just a variable. Predict both outputs, paying attention to whether the second one keeps its decimal point.

const count = 2;const label = "item";console.log(`You have ${count} ${label}${count === 1 ? "" : "s"}.`);console.log(`Total: ${count * 1.5}`);

What does `${["a", "b"]}` produce?

You have `const name = "Ada";` and want the string "Hello Ada". Which line produces it?

Write it yourself

Exercise · core · 6 tests

Format one line of a receipt

Write a function `formatReceiptLine(line)` that takes an object with `item`, `quantity` and `unitPrice`, and returns one formatted line of text. The exact shape is: the item name, a space, a lower-case x with the quantity stuck to it, a space, an equals sign, a space, and then the total (quantity times unit price) written to exactly two decimal places. For `{ item: "Notebook", quantity: 3, unitPrice: 4.5 }` that is `"Notebook x3 = 13.50"`. Two decimal places always, even when the total is a whole number: `"20.00"`, not `"20"`. `(4).toFixed(2)` gives you the string "4.00", which is the tool for that job.

What your code must do

Returns a string of the form "<item> x<quantity> = <total>", where total is quantity * unitPrice written with exactly two decimal places, for any quantity including 0 and any unit price including ones that need rounding. No leading or trailing spaces.

Define formatReceiptLine at the top level of your code — the tests call it by name.

Runs on your device in a sandbox with no network and no access to this page.

Worth remembering

  • Which quote character allows ${...} substitution, and what does it do?

    Only backticks. `Hello ${name}` evaluates the expression inside the braces once, converts the result to text and drops it in. Inside "..." or '...' the same characters are just literal text.

  • Why does your log say [object Object]?

    An object was dropped into ${} or joined with +, and an object's default text form is [object Object]. Use JSON.stringify(value) to see its contents instead.

Check this lesson against the source

We wrote the explanation; we did not invent the facts. This is the page that backs them.

MDN — Template literals (Template strings)

Check there: Backtick-delimited strings support ${expression} substitution and multi-line text; the page also documents escaping a backtick with \` and a dollar-brace with \${, and introduces tagged templates.

MDN — Number.prototype.toFixed()

Check there: toFixed(digits) returns a STRING with the number written to that many decimal places.

MDN — String concatenation with +

Check there: When either operand of + is a string, the other is converted to a string and the two are joined.

Prefer to read the source in a structured breakdown? Turn this doc into a breakdown

0 of 1 exercise in this lesson solved on this device

Consent version 2026-07-31.1

Cookie preferences