Из этого материала вы узнаете о различиях между обычными строковыми значениями, задаваемыми с помощью одинарных или двойных кавычек, и шаблонными литералами. Вы ознакомитесь с различными способами объявления строк с разными характеристиками, включая многострочные строки и динамические строки, меняющиеся в зависимости от значения некоей переменной или некоего выражения. Вы научитесь работать с теговыми шаблонами и увидите реальные примеры их использования.
Объявление строк
В этом разделе мы вспомним о том, как объявляются строки, описываемые с использованием одинарных или двойных кавычек, а затем взглянем на то, как то же самое делается при применении шаблонных литералов.
Строку в JavaScript можно представить как последовательность символов, заключённую в одинарные кавычки (
' '
):
const single = 'Every day is a good day when you paint.'
Ещё один вариант объявления строк заключается в использовании двойных кавычек ( ):
const double = "Be so very light. Be a gentle whisper."
В JavaScript между такими строками нет серьёзных различий. В других языках использование разных кавычек при объявлении строк может означать, например, то, что строки одного вида можно интерполировать, а другие нет. Здесь мы понимаем под интерполяцией возможность вычисления значений выражений-местозаполнителей, играющих роль динамических частей строк и участвующих в формировании итоговых строковых значений.
Какие именно строки использовать, объявленные с одинарными или с двойными кавычками, это, по большей части, дело личных предпочтений программиста и используемых им соглашений по написанию кода. Но если в строке, ограниченной кавычками одного из этих видов, встречаются кавычки того же вида, их нужно экранировать. Кавычки же другого вида в подобных строках в экранировании не нуждаются.
// Экранирование одинарных кавычек в строке, ограниченной одинарными кавычками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);
Вызов пары методов
log()
приведёт к тому, что в
консоль попадут две одинаковых строки.
"We don't make mistakes. We just have happy accidents." - Bob Ross"We don't make mistakes. We just have happy accidents." - Bob Ross
Шаблонные литералы, с другой стороны, объявляют с использованием обратных кавычек (
` `
):
const template = `Find freedom on this canvas.`
Здесь не нужно экранировать одинарные или двойные кавычки:
const template = `"We don't make mistakes. We just have happy accidents." - Bob Ross
Но обратные кавычки в таких строках экранировать необходимо:
const template = `Template literals use the \` character.`
Шаблонные литералы имеют все возможности, которые есть у обычных строк. Поэтому вы, вероятно, можете заменить все строки в своём проекте на шаблонные литералы и при этом ничего не потерять. Однако чаще всего в соглашениях, касающихся написания кода, указывают, что шаблонные литералы должны использоваться только тогда, когда нужны их особые возможности. Обычные же строки всегда, ради поддержания единообразия кода, объявляют с использованием или одинарных, или двойных кавычек. Кодовую базу проекта, при написании которой следуют этому стандарту, будет легче читать разработчикам, с ней ранее не знакомым.
Теперь, когда мы поговорили об объявлении строк с использованием одинарных, двойных и обратных кавычек, мы можем перейти к разбору первой сильной стороны шаблонных литералов. А именно к возможности описания многострочных строк.
Многострочные строки
В этом разделе мы сначала поговорим о том, как многострочные строки объявлялись до ES6, а потом остановимся на том, как решение этой задачи упрощают шаблонные литералы.
Изначально, если нужно было ввести в текстовом редакторе строковую переменную, состоящую из нескольких строк, использовался оператор конкатенации строк. Следующий пример конкатенации строк иллюстрирует эту идею:
const address ='Homer J. Simpson' +'742 Evergreen Terrace' +'Springfield'
Данный подход может позволить разбивать длинные строки на небольшие фрагменты и располагать их в текстовом редакторе на нескольких строках. Но это никак не влияет на то, какой получится итоговая строка. В данном случае значение строковой константы будет располагаться в одной строке. Те части, из которых собрано строковое значение, не будут разделены символами перевода строки или пробелами. Если вывести в консоль константу
address
, то там появится следующее:
Homer J. Simpson742 Evergreen TerraceSpringfield
Ещё один подход к записи подобных строк в редакторах кода заключается в использовании символа обратной косой черты (
\
), который ставится в конце фрагментов строк, и
после которого, с новой строки, располагаются новые фрагменты:
const address ='Homer J. Simpson\742 Evergreen Terrace\Springfield'
При таком подходе сохраняются, например, пробелы, находящиеся перед фрагментами строки, но значение переменной, если вывести его в консоль, снова будет представлено единственной строкой:
Homer J. Simpson 742 Evergreen Terrace Springfield
Создать настоящую многострочную строку можно, используя символ перевода строки (
\n
):
const address ='Homer J. Simpson\n' +'742 Evergreen Terrace\n' +'Springfield'
При выводе в консоль строкового значения, хранящегося в
address
, это значение будет занимать несколько
строк:
Homer J. Simpson742 Evergreen TerraceSpringfield
Правда, использовать символ перевода строки для создания многострочных строк не особенно удобно и просто. С другой стороны, создание многострочных строк с использованием шаблонных литералов выглядит гораздо проще и удобнее. Не нужно конкатенировать строки, не нужно использовать символ новой строки или обратную косую черту. Для создания многострочных строк с использованием шаблонных литералов достаточно просто, в конце очередного фрагмента строки, нажать клавишу
Enter
, и продолжить вводить следующую
строку шаблонного литерала:
const address = `Homer J. Simpson742 Evergreen TerraceSpringfield`
Если вывести эту константу в консоль, то выглядеть текст будет так же, как в редакторе:
Homer J. Simpson742 Evergreen TerraceSpringfield
Тут надо учитывать то, что если между символами обратных кавычек содержатся пробелы, используемые для выравнивания кода, эти пробелы попадут в итоговый шаблонный литерал. Рассмотрим следующий пример:
const address = `Homer J. Simpson742 Evergreen TerraceSpringfield`
Хотя такой стиль написания кода упрощает его чтение, то, что попадёт в консоль после его вывода, будет выглядеть не очень-то привлекательно:
Homer J. Simpson742 Evergreen TerraceSpringfield
Теперь, разобравшись с многострочными строками, давайте поговорим о том, как в строки, объявленные разными способами, можно встраивать результаты вычисления различных выражений, то есть поговорим об интерполяции выражений.
Интерполяция выражений
Раньше, до выхода ES6, для создания динамических строк, в формировании которых участвовали значения переменных или выражения, использовалась конкатенация:
const method = 'concatenation'const dynamicString = 'This string is using ' + method + '.'
Если вывести
dynamicString
в консоль, то получится
следующее:
This string is using concatenation.
При использовании шаблонных литералов выражения можно внедрять в строку с использованием местозаполнителей. Местозаполнитель представляет собой конструкцию вида
${}
. При этом всё,
что содержится в фигурных скобках, рассматривается как
JavaScript-код, а всё, находящееся за пределами этой конструкции,
рассматривается как строка:
const method = 'interpolation'const dynamicString = `This string is using ${method}.`
При выводе
dynamicString
в консоль получится следующий
результат:
This string is using interpolation.
Распространённый пример встраивания значений в строки это создание динамических URL. Использование для этой цели конкатенации приводит к появлению громоздких и неудобных конструкций. Например, вот функция, которая генерирует строку доступа OAuth:
function createOAuthString(host, clientId, scope) {return host + '/login/oauth/authorize?client_id=' + clientId + '&scope=' + scope}createOAuthString('https://github.com', 'abc123', 'repo,user')
Если вывести в консоль результат работы этой функции, то получится следующее:
https://github.com/login/oauth/authorize?client_id=abc123&scope=repo,user
При использовании интерполяции программистам больше не нужно внимательно следить за кавычками, ограничивающими фрагменты строки, и за тем, где именно расположен оператор конкатенации. Вот тот же пример, переписанный с использованием шаблонных литералов:
function createOAuthString(host, clientId, scope) {return `${host}/login/oauth/authorize?client_id=${clientId}&scope=${scope}`}createOAuthString('https://github.com', 'abc123', 'repo,user')
Результат работы функции будет таким:
https://github.com/login/oauth/authorize?client_id=abc123&scope=repo,user
Для того чтобы убрать пробелы в начале и в конце строки, создаваемой с помощью шаблонного литерала, можно воспользоваться методом trim(). Например, в следующем фрагменте кода для создания HTML-элемента с настраиваемой ссылкой используется стрелочная функция:
const menuItem = (url, link) =>`<li><a href="${url}">${link}</a></li>`.trim()menuItem('https://google.com', 'Google')
Из итоговой строки будут удалены начальные и конечные пробелы, что позволит обеспечить правильность рендеринга элемента:
<li><a href="http://personeltest.ru/aways/google.com">Google</a></li>
Интерполировать можно целые выражения, а не только переменные. Например как здесь, где в строку встраивается результат сложения двух чисел:
const sum = (x, y) => x + yconst x = 5const y = 100const string = `The sum of ${x} and ${y} is ${sum(x, y)}.`console.log(string)
Здесь объявлена функция
sum()
и константы
x
и y
. После этого в строке используется
и функция, и эти константы. Вот как выглядит константа
string
, выведенная в консоль:
The sum of 5 and 100 is 105.
Этот механизм может оказаться особенно полезным при использовании тернарного оператора, который позволяет проверять условия при формировании строки:
const age = 19const message = `You can ${age < 21 ? 'not' : ''} view this page`console.log(message)
Константа
message
, выведенная в консоль, может менять
в зависимости от того, больше или меньше 21 значение, хранящееся в
age
. Так как в нашем примере это значение равняется
19, в консоль попадёт следующее:
You can not view this page
Теперь вы знаете о том, какую пользу можно извлечь из интерполяции выражений при применения шаблонных литералов. В следующем разделе мы пойдём ещё дальше и исследуем теговые шаблоны, поговорим о работе с выражениями, передаваемыми в области, соответствующие местозаполнителям.
Теговые шаблоны
Теговые шаблоны являются расширенной формой шаблонных литералов. Теговые шаблоны начинаются с теговой функции, которая разбирает шаблонный литерал, давая разработчику более высокий уровень контроля над процессом формирования динамических строк.
В следующем примере мы создаём функцию
tag
, которую
планируем использовать в роли функции, с помощью которой
выполняются операции над теговым шаблоном. Первым параметром этой
функции, носящим имя strings
, является массив
строковых литералов. Выражения, встраиваемые в строку, помещены во
второй параметр с использованием
синтаксиса оставшихся параметров. Для того чтобы увидеть
содержимое этих параметров их можно вывести в консоль:
function tag(strings, ...expressions) {console.log(strings)console.log(expressions)}
Если при создании тегового шаблона воспользоваться функцией
tag
, то может получиться такая конструкция:
const string = tag`This is a string with ${true} and ${false} and ${100} interpolated inside.`
Так как в функции
tag
выполняется вывод в консоль
strings
и expressions
, при выполнении
этого кода в консоль попадёт следующее:
["This is a string with ", " and ", " and ", " interpolated inside."][true, false, 100]
Видно, что первый параметр,
strings
, это массив,
содержащий все строковые литералы:
"This is a string with "" and "" and "" interpolated inside."
У этого аргумента ещё есть свойство
raw
, к которому
можно обратиться как к strings.raw
. Оно содержит
строку, в которой не были обработаны управляющие
последовательности. Например, \n
будет просто символом
\n
, а не командой перевода строки.Второй аргумент,
...expressions
, это массив,
содержащий все выражения:
truefalse100
В результате оказывается, что функции тегового шаблона
tag
передаются строковые литералы и выражения.
Обратите внимание на то, что функция не обязана возвращать строку.
Она может работать с переданными ей значениями и возвращать всё что
угодно. Например, у нас может быть функция, которая ни на что не
обращает внимания и просто возвращает null
. Именно так
написана функция returnsNull
в следующем примере:
function returnsNull(strings, ...expressions) {return null}const string = returnsNull`Does this work?`console.log(string)
В результате выполнения этого кода в консоль попадёт следующее:
null
В качестве примера действия, которое можно выполнить в теговом шаблоне, можно привести внесение изменений в каждое из выражений, например, таких изменений, которые заключаются в помещении выражений в HTML-теги. Создадим функцию
bold
, которая
добавляет теги <strong>
и
</strong>
в начало и в конец каждого
выражения:
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)
Здесь, для обхода массива
expressions
, используется
цикл
forEach. Каждый элемент заключается в теги
<strong></strong>
.
This is a string with <strong>true</strong> and <strong>false</strong> and <strong>100</strong> interpolated inside.
В популярных JavaScript-библиотеках можно найти несколько примеров использования теговых шаблонов. Так, в библиотеке graphql-tag используется шаблонный литерал
gql
для
разбора строк запроса GraphQL и
преобразования их в абстрактное синтаксическое дерево (abstract
syntax tree, AST), понятное GraphQL:
import gql from 'graphql-tag'// Запрос для получения имени и фамилии пользователя 5const query = gql`{user(id: 5) {firstNamelastName}}`
Функции теговых шаблонов используются и в библиотеке styled-components, что позволяет создавать новые компоненты React из обычных элементов DOM и применять к ним дополнительные CSS-стили:
import styled from 'styled-components'const Button = styled.button`color: magenta;`// <Button> теперь может использоваться как компонент
Кроме того, можно пользоваться стандартным методом String.raw, применяя его к теговым шаблонам для того чтобы предотвратить обработку управляющих последовательностей:
const rawString = String.raw`I want to write /n without it being escaped.`console.log(rawString)
В консоль после выполнения этого кода попадёт следующее:
I want to write /n without it being escaped.
Итоги
В этом материале мы вспомнили основные сведения об обычных строковых литералах, оформляемых с помощью одинарных или двойных кавычек, а так же поговорили о шаблонных литералах и о теговых шаблонах. Шаблонные литералы упрощают решение множества задач, связанных с обработкой строк. В частности, речь идёт о встраивании в строки различных значений и о создании многострочных строк без использования конкатенации или экранирования. Теговые шаблоны это полезная продвинутая возможность шаблонных литералов, которая используется во многих популярных библиотеках.
А вы пользуетесь шаблонными литералами?