A Path to Understanding Template Literals in JavaScript

The 2015 ECMAScript specification ( ES6 ) added a new feature to JavaScript - template literals. Template literals give us a new mechanism for creating string values... This mechanism has many powerful features, such as simplifying the creation of multi-line constructs and using placeholders to embed expression results in strings. In addition, there is another possibility here - tagged template literals. This is an extended form of template literals. Tag templates allow you to create strings using expressions inside strings and using special functions. All of this expands the ability of programmers to work with strings, allowing, for example, to create dynamic strings that can be URLs , or write functions to fine-tune HTML elements .







In this article, you will learn about the differences between regular string values, specified with single or double quotes, and template literals. You will learn about different ways of declaring strings with different characteristics, including multiline strings and dynamic strings that change depending on the value of a variable or expression. You will learn how to work with tag templates and see real-world examples of their use.



Declaring strings



In this section, we recall how strings are declared using single or double quotes, and then take a look at how the same is done when using template literals.



A JavaScript string can be thought of as a sequence of characters enclosed in single quotes ( ' '):



const single = 'Every day is a good day when you paint.'


Another way to declare strings is to use double quotes ( " "):



const double = "Be so very light. Be a gentle whisper."


In JavaScript, there are no major differences between such strings. In other languages, using different quotation marks when declaring strings can mean, for example, that strings of one kind can be interpolated while others cannot. Here we mean by "interpolation" the ability to compute the values ​​of placeholder expressions that play the role of dynamic parts of strings and participate in the formation of the resulting string values.



Which strings to use when declared with single or double quotes is largely a matter of personal preference and coding conventions. However, if the same type of quotation mark occurs in a string delimited by one of these types of quotation marks, they must be escaped . Quotes of a different kind in such strings do not need escaping.



//     ,   
const single = '"We don\'t make mistakes. We just have happy accidents." - Bob Ross'

//     ,   
const double = "\"We don't make mistakes. We just have happy accidents.\" - Bob Ross"

console.log(single);
console.log(double);


Calling a pair of methods log()will result in two identical lines being sent to the console .



"We don't make mistakes. We just have happy accidents." - Bob Ross
"We don't make mistakes. We just have happy accidents." - Bob Ross


Template literals, on the other hand, are declared using backticks ( ` `):



const template = `Find freedom on this canvas.`


There is no need to escape single or double quotes here:



const template = `"We don't make mistakes. We just have happy accidents." - Bob Ross


But backticks in such strings must be escaped:



const template = `Template literals use the \` character.`


Template literals have all the capabilities of regular strings. Therefore, you can probably replace all strings in your project with template literals without losing anything. Most often, however, coding conventions specify that template literals should only be used when their special capabilities are needed. Ordinary strings are always declared using either single or double quotes to maintain code consistency. The code base of the project, when writing which follows this standard, will be easier to read for developers who are not previously familiar with it.



Now that we've talked about declaring strings using single quotes, double quotes, and backticks, we can move on to the first strength of template literals. Namely - to the possibility of describing multi-line strings.



Multi-line strings



In this section, we'll first talk about how multiline strings were declared before ES6, and then we'll look at how template literals simplify this task.



Initially, if you had to enter a string variable consisting of several lines in a text editor, the string concatenation operator was used . The following string concatenation example illustrates this idea:



const address =
  'Homer J. Simpson' +
  '742 Evergreen Terrace' +
  'Springfield'


This approach can allow you to break long lines into small chunks and arrange them in a text editor on several lines. But this does not in any way affect how the final row will turn out. In this case, the value of the string constant will be located on one line. The parts from which the string value is assembled will not be separated by line feeds or spaces. If you print a constant to the console address, the following will appear there:



Homer J. Simpson742 Evergreen TerraceSpringfield


Another approach to writing such lines in code editors is to use the backslash character ( \), which is placed at the end of line fragments, and after which, on a new line, new fragments are located:



const address =
  'Homer J. Simpson\
  742 Evergreen Terrace\
  Springfield'


With this approach, for example, the spaces before the fragments of the line are preserved, but the value of the variable, if you print it to the console, will again be represented by a single line:



Homer J. Simpson  742 Evergreen Terrace  Springfield


You can create a real multiline string using the linefeed character ( \n):



const address =
  'Homer J. Simpson\n' +
  '742 Evergreen Terrace\n' +
  'Springfield'


When displaying a string value stored in the console address, this value will span multiple lines:



Homer J. Simpson
742 Evergreen Terrace
Springfield


However, using the newline character to create multi-line strings is not particularly convenient and easy. On the other hand, creating multi-line strings using template literals is much easier and more convenient. No need to concatenate strings, no need to use newline or backslash. To create multi-line strings using template literals, it is quite simple, at the end of the next fragment of a line, press the key Enter, and continue entering the next line of the template literal:



const address = `Homer J. Simpson
742 Evergreen Terrace
Springfield`


If you output this constant to the console, the text will look the same as in the editor:



Homer J. Simpson
742 Evergreen Terrace
Springfield


Here it should be borne in mind that if there are spaces between backticks used to align the code, these spaces will be included in the final template literal. Consider the following example:



const address = `Homer J. Simpson
                 742 Evergreen Terrace
                 Springfield`


Although this style of coding makes it easier to read, what gets to the console after outputting it won't look very attractive:



Homer J. Simpson
                 742 Evergreen Terrace
                 Springfield


Now, having dealt with multi-line strings, let's talk about how you can embed the results of evaluating various expressions into strings declared in different ways, that is, let's talk about interpolating expressions.



Expression Interpolation



Previously, before ES6, concatenation was used to create dynamic strings that involved variable or expression values:



const method = 'concatenation'
const dynamicString = 'This string is using ' + method + '.'


If you output dynamicStringto the console, you get the following:



This string is using concatenation.


When using template literals, expressions can be embedded in the string using placeholders. A placeholder is a view construct ${}. In this case, everything contained in curly braces is considered as JavaScript code, and everything outside this construction is considered as a string:



const method = 'interpolation'
const dynamicString = `This string is using ${method}.`


When outputting dynamicStringto the console, you get the following result:



This string is using interpolation.


A common example of embedding values ​​in strings is creating dynamic URLs. The use of concatenation for this purpose leads to the appearance of cumbersome and inconvenient structures. For example, here's a function that generates an OAuth access string :



function createOAuthString(host, clientId, scope) {
  return host + '/login/oauth/authorize?client_id=' + clientId + '&scope=' + scope
}

createOAuthString('https://github.com', 'abc123', 'repo,user')


If you print the result of this function to the console, you get the following:



https://github.com/login/oauth/authorize?client_id=abc123&scope=repo,user


When using interpolation, programmers no longer need to be careful about the quotation marks that delimit portions of the string, and where exactly the concatenation operator is located. Here is the same example, rewritten using template literals:



function createOAuthString(host, clientId, scope) {
  return `${host}/login/oauth/authorize?client_id=${clientId}&scope=${scope}`
}

createOAuthString('https://github.com', 'abc123', 'repo,user')


The result of the function will be as follows:



https://github.com/login/oauth/authorize?client_id=abc123&scope=repo,user


You can use the trim () method to remove leading and trailing whitespace from a string created with a template literal . For example, in the following code snippet to create an HTML elementwith a custom reference, an arrow function is used :



const menuItem = (url, link) =>
  `
<li>
  <a href="${url}">${link}</a>
</li>
`.trim()

menuItem('https://google.com', 'Google')


Leading and trailing spaces will be removed from the final line to ensure that the element is rendered correctly:



<li>
  <a href="https://google.com">Google</a>
</li>


Whole expressions can be interpolated, not just variables. For example - like here, where the result of adding two numbers is embedded in a string:



const sum = (x, y) => x + y
const x = 5
const y = 100
const string = `The sum of ${x} and ${y} is ${sum(x, y)}.`

console.log(string)


Here function sum()and constants are declared xand y. After that, the line uses both the function and these constants. This is what the constant looks like stringwhen printed to the console:



The sum of 5 and 100 is 105.


This mechanism can be especially useful when using the ternary operator , which allows you to check conditions when forming a string:



const age = 19
const message = `You can ${age < 21 ? 'not' : ''} view this page`
console.log(message)


The constant messageprinted to the console can change, depending on whether it is greater than or less than 21, the value stored in age. Since this value is 19 in our example, the following will be sent to the console:



You can not view this page


Now you know how you can benefit from expression interpolation when using template literals. In the next section, we'll go further and explore tagging patterns, and talk about working with expressions passed in scopes that match placeholders.



Tag templates



Tag templates are an extended form of template literals. Tagged templates begin with a tagged function that parses the template literal, giving the developer more control over the dynamic string generation process.



In the following example, we create a function tagthat we plan to use in the role of a function that performs operations on a tag template. The first named parameter to this function stringsis an array of string literals. Inline expressions are placed in the second parameter using the syntax of the remaining parameters . In order to see the contents of these parameters, they can be displayed in the console:



function tag(strings, ...expressions) {
  console.log(strings)
  console.log(expressions)
}


If you use a function when creating a tag template tag, you can get the following construction:



const string = tag`This is a string with ${true} and ${false} and ${100} interpolated inside.`


Since the function tagperforms output to the console stringsand expressions, when executing this code, the following will be sent to the console:



["This is a string with ", " and ", " and ", " interpolated inside."]
[true, false, 100]


You can see that the first parameter strings,, is an array containing all string literals:



"This is a string with "
" and "
" and "
" interpolated inside."


This argument also has a property rawthat you can refer to as strings.raw. It contains a line on which no escape sequences have been processed. For example, it \nwill be just a character \n, not a line feed command.



The second argument,, ...expressionsis an array containing all expressions:



true
false
100


As a result, it appears that tagstring literals and expressions are passed to the tag template function . Note that the function is not required to return a string. It can work with the values ​​passed to it and return anything. For example, we might have a function that pays no attention to anything and just returns null. This is how the function is written returnsNullin the following example:



function returnsNull(strings, ...expressions) {
  return null
}

const string = returnsNull`Does this work?`
console.log(string)


As a result of executing this code, the following will appear in the console:



null


As an example of what you can do in a tagged template, you can make changes to each of the expressions, such as changes to include expressions in HTML tags. Let's create a function boldthat adds tags to <strong>both </strong>the beginning and the end of each expression:



function bold(strings, ...expressions) {
  let finalString = ''

  //    
  expressions.forEach((value, i) => {
    finalString += `${strings[i]}<strong>${value}</strong>`
  })

  //    
  finalString += strings[strings.length - 1]

  return finalString
}

const string = bold`This is a string with ${true} and ${false} and ${100} interpolated inside.`

console.log(string)


Here, expressionsa forEach loop is used to traverse the array . Each element is enclosed in tags <strong></strong>.



This is a string with <strong>true</strong> and <strong>false</strong> and <strong>100</strong> interpolated inside.


There are several examples of using tag templates in popular JavaScript libraries. For example, the graphql-tag library uses a template literal gqlto parse GraphQL query strings and transform them into an abstract syntax tree (AST) that GraphQL understands:



import gql from 'graphql-tag'

//        5
const query = gql`
  {
    user(id: 5) {
      firstName
      lastName
    }
  }
`


The styled-components library also uses tagging functionality to create new React components from regular DOM elements and apply additional CSS styles to them :



import styled from 'styled-components'

const Button = styled.button`
  color: magenta;
`

// <Button>     


Alternatively, you can use the standard String.raw method to apply it to tagged templates to prevent the processing of escape sequences:



const rawString = String.raw`I want to write /n without it being escaped.`
console.log(rawString)


The following will appear in the console after executing this code:



I want to write /n without it being escaped.


Outcome



In this article, we remembered the basic information about ordinary string literals, formatted with single or double quotes, and also talked about template literals and tag templates. Template literals simplify many string-processing tasks. In particular, we are talking about embedding different values ​​in strings and about creating multi-line strings without using concatenation or escaping. Tagging is a useful advanced template literal feature that is used in many popular libraries.



Do you use template literals?






All Articles