Template Literals
Tags: javascript, webdev, beginners, tutorial
Published: 2021-10-05 17:12:52

*This article is part of the first installment of a series I'm calling __JavaScript You Must Know__. The aim of this series is to go over various fundamentals of the JavaScript language that a developer must know/understand before moving forward with any of the modern JavaScript frameworks like React, Angular, and Vue. Learning these fundamentals in parallel with the frameworks would also be acceptable.*

*This first installment of the series focuses on syntax-related topics and is called __JavaScript You Must Know -- Essential Syntax__.*

---

JavaScript used to have two ways of writing a string: using **single quotes** or using **double quotes**. With template literals, we now have a third way: using backticks. Looks something like this:

```js
let myBelovedString = `A dance under the moonlight.`;
```

Once again, those are backticks and not single quotes.

So why introduce another way of writing strings? Well, to give us, the programmers, access to the following features:

* Easier string formatting
* String interpolation
* Tagged templates

Let's go over those features one by one.

## Easier String Formatting

Writing multi-line strings in JavaScript, if you're using single or double quoted strings, requires the use of special characters such as `\n` (new line) or `\t` (tab). An example.

```js
let myBelovedString = "'tis nothing...\nbut a scratch";

/**
 * can't do the following as it will generate an error
 *
 * let myBelovedString = "'tis nothing...
 * but a scratch";
 *
 **/

console.log(myBelovedString);
```

> [console output]:
  >
  > ```
  > 'tis nothing...
  > but a scratch
  > ```
  >

As the comment in the code example above says, if we'd simply pressed the enter key at the end of the first line (expecting a new line in the output) and had continued with our string, it would actually generate an error. The reason is that the newline character that is inserted by pressing the enter key is not interpreted as part of the string by the JavaScript engine. As a result, the engine thinks that the newline charater is part of the code instead of the string and assumes that it indicates the end of the JavaScript statement.

When using template literals on the other hand, the newline character is considered part of the string. In fact, all whitespace characters (spaces, tabs, newline) are interpreted as part of the string. As a result, multi-line strings become much easier to format. All this means is that string formatting just became a whole lot easier and can be done without the use of special escape characters such as `\n`. The example above would become:

```js
let myBelovedString = `'tis nothing...
but a scratch`;

console.log(myBelovedString);
```

> [console output]:
  >
  > ```
  > 'tis nothing...
  > but a scratch
  > ```
  >

> 💡 just a tip
>
> If we try to do something like this:
  > ```js
  > let myBelovedString = `
  > 'tis nothing...
  > but a scratch`;
  > ```
  >
> It will introduce a blank line at the start which isn't exactly desirable. But we can use the `trim()` function to get rid of the newline character at the beginning of the string:
>
  > ```js
  > let myBelovedString = `
  > 'tis nothing...
  > but a scratch`.trim();
  >```
  >

# String Interpolation

Definitely one of the best features added to JavaScript. String interpolation allows us to put any valid JavaScript expression inside our template string and it will be evaluated during runtime. The concept itself is, of course, not new. It was just done differently before: using concatenation. Let's first look at the old-school way of doing things.

```js
const myName = "Plump Sunny";
console.log("Hi, my name is " + myName + "."); // output: "Hi, my name is Plump Sunny."
```

Leveraging string interpolation when using template literals, the same result can be achieved as follows:

```js
const myName = "Plump Sunny";
console.log(`Hi, my name is ${myName}.`); // output: "Hi, my name is Plump Sunny."
```

Simple, readable, elegant, with no +s all over the place. As you may have noticed, we have to tell the JavaScript engine which part of the string needs to be interpolated. This is done by using this syntax: `${your JS expression goes here}`. Any valid JavaScript expression can be put inside the curly braces. The expression will be evaluated and the result will be part of the string. This includes arithmetic expressions and function calls.

```js
function publicServiceMessage() {
  return "Exercise is good.";
}

const js = {
  fullName: "JavaScript",
  yearCreated: 1995
};

const message = `
Today's PSA: ${publicServiceMessage()}
Fun fact: ${js.fullName} was created in the year ${js.yearCreated}.`.trim();

console.log(message);
```

> [console log]:
>
  > ```
  > "Today's PSA: Exercise is good.
  > Fun fact: JavaScript was created in the year 1995."
  > ```
  >

Note how straightforward it was to format our final multi-line message using template literals.

Two final points to remember:

* If you wish to output backticks in your string, just escape them with a backslash.
* String interpolation expects a JavaScript *expression* inside the curly braces. This means that JavaScript statements, such as `if`, `for`, etc., will not work. And since the ternary operator defines a JavaScript expression, it can be used instead of an `if` statement.

## Tagged Template Literals

Let's revisit a simple template literal.

```js
let aSimpleTemplateLiteral = `A simple template literal, this is.`;
```

Another feature that is available to template literals (or template strings) is the ability to **tag** them. Resulting in **tagged template literals**. It looks like this:

```js
let aTaggedTemplateLiteral = capitalize`A tagged template literal, this is.`;
```

A *tag* (`capitalize`) has been added just before the first backtick of our template literal resulting in a **tagged template literal**. By tagging it like this we're telling the JavaScript engine to do the following:

* call a function named `capitalize`
* pass the string between the backticks to this function (in a pre-defined way)

The value returned by `capitalize()` will be assigned to the variable `aTaggedTemplateLiteral`. So basically, we've introduced a **pre-processing** step where we can manipulate the string however we like before it is assigned to the variable.

I'd like to emphasize here that a tag is simply a function call and anything returned by that function is assigned to the variable.

```js
function capitalize() {
  return "Sticks and stones my friend.";
}

let myFinalString = capitalize`This string doesn't really matter right now.`;

console.log(myFinalString); // output: "Sticks and stones my friend."
```

We didn't even bother to receive the arguments passed to `capitalize()` (because we haven't covered that topic yet). We have simply returned a string which was eventually assigned to `myFinalString`.

Now, before we discuss how the string is passed to the pre-processing function, we need to introduce some expressions in the string. As always, we will start with a simple example.

```js
function capitalize(strings, name, age) {
  return "Not doing anything yet.";
}

const myName = "Plump Sunny";
const myAge = 32;

let myFinalString = capitalize`Hi, my name is ${myName} and I'm ${myAge}.`;

console.log(myFinalString); // output: "Not doing anything yet."
```

Now, finally, let's see how the string between the backticks is passed to the function (`capitalize()` in this case):

1. Before passing anything to `capitalize()`, the string will be broken down. It will be broken down into **plain text tokens** and **expressions** (as you might remember, the dollar and curly braces syntax can accept any JavaScript expression). For our example, this break down would look something like this:

  * text_token_1: "Hi, my name is "
  * expression_1: `myName`
  * text_token_2: " and I'm "
  * expression_2: `myAge`
  * text_token_3: "."

2. Next, an array will be created with just the plain text tokens, while maintaining the order that they appear in the original string. This array of plain text tokens will be passed as the first argument to `capitalize()`. In our example, looking at the function declaration of `capitalize()`, this array will be passed to `strings` and will look like this:

  * `["Hi, my name is ", " and I'm ", "."]`

3. Lastly, the expressions in the original string will be evaluated (in the order that they appear in the string) and passed to the function as individual arguments. In our example, `name` will receive the value of `myName` and `age` will receive the value of `myAge`.

We now have the ability to manipulate the string however we see fit. To keep it simple at first, we will simply return the same string but with the name in all caps.

```js
function capitalize(strings, name, age) {
  return `${string[0]}${name.toUpperCase()}${strings[1]}${age}${strings[2]}`;
}

const myName = "Plump Sunny";
const myAge = 32;

let myFinalString = capitalize`Hi, my name is ${myName} and I'm ${myAge}.`;

console.log(myFinalString); // output: "Hi, my name is PLUMP SUNNY and I'm 32."
```

This doesn't feel right though (actually, it feels all kinds of wrong). Everything is hard coded inside `capitalize()`. A very common pattern is to use **rest parameters** combined with tagged templates. Since the expressions inside the original string are passed as individual arguments to the pre-processing function, using rest parameters gives us a convenient array of all the expressions of the original string. This allows us to build our final string programmatically instead of hard coding everything. An example should clear things up.

Let's redefine `capitalize()` using rest parameters and build our string programmatically.

```js
function capitalize(strings, ...expressions) {
  let finalString = "";

  strings.forEach((token, index) => {
    finalString += `${token}${expressions[index]}`;
  });

  return finalString;
}

const myName = "Plump Sunny";
const myAge = 32;

let myFinalString = capitalize`Hi, my name is ${myName} and I'm ${myAge}.`;

console.log(myFinalString); // output: "Hi, my name is Plump Sunny and I'm 32.undefined"
```

Much better. But we're not doing anything to the string. We know that the first expression in the string is the name. This means that inside `capitalize()`, when the index is 0, we will call `toUpperCase()` to the expression and will return the expression as it is otherwise (we'll deal with the `undefined` at the end in the next step).

```js
function capitalize(strings, ...expressions) {
  let finalString = "";

  strings.forEach((token, index) => {
    finalString += `${token}${(index == 0) ? expressions[index].toUpperCase() : expression[index]}`;
  });

  return finalString;
}

const myName = "Plump Sunny";
const myAge = 32;

let myFinalString = capitalize`Hi, my name is ${myName} and I'm ${myAge}.`;

console.log(myFinalString); // output: "Hi, my name is PLUMP SUNNY and I'm 32.undefined"
```

Now let's deal with the `undefined` at the end of the string. This is because the length of the `strings` and `expressions` arrays don't match and when we try to access an index on `expressions` that doesn't exist it returns `undefined`. To solve this, consider the following nifty trick:

```js
(expression[index] || "")
```

The expression above will return `expression[index]` if it exists and will return an empty string otherwise. Let's plug this is in our `capitalize()` function.

```js
function capitalize(strings, ...expressions) {
  let finalString = "";

  strings.forEach((token, index) => {
    finalString += `${token}${(index == 0) ? expressions[index].toUpperCase() : (expression[index] || "")}`;
  });

  return finalString;
}

const myName = "Plump Sunny";
const myAge = 32;

let myFinalString = capitalize`Hi, my name is ${myName} and I'm ${myAge}.`;

console.log(myFinalString); // output: "Hi, my name is PLUMP SUNNY and I'm 32."
```

> 💡 just a tip
>
> In our example above, the template literal ended on a plain text token (the full stop). But let's say our template literal didn't have that full stop at the end and ended on an expression as a result.
> ```js
> let myFinalString = capitalize`Hi, my name is ${myName} and I'm ${myAge}`;
> ```
>
> In this case, when we break the template literal down into plain text tokens and expressions, it comes out to two of each. So one might think that the `strings` array in this case will be: `["Hi, my name is ", " and I'm "]`.
>
> In reality, if a template literal ends on an expression, then the last element in the array of plain text tokens will be an empty string. In our case, the `strings` array will look like this: `["Hi, my name is ", " and I'm ", ""].

---

👉🏻 Subscribe to my newsletter: [click here](https://www.bracketsinstitute.com/newsletter-subscription)

👉🏻 Follow me on twitter: [click here](https://twitter.com/therealnrf)

---