Шаблоны строк (template strings / template literals) позволяют вставлять в строку различные значения. Подобный прием еще называют интерполяцией. Для этого строки заключаются в косые кавычки, а вставляемое значение предваряется символом $ и заключается в фигурные скобки:
const name = "Tom"; const hello = `Hello ${name}`; console.log(hello); // Hello Tom
Здесь на место ${name}
будет вставляться значение константы name
. Таким образом, из шаблона `Hello ${name}`
мы получим строку
Hello Tom
.
Подобным образом в строку можно вставлять сразу несколько значений:
const name = "Tom"; const age = 37; const userInfo = `${name} is ${age} years old`; console.log(userInfo); // Tom is 37 years old
Также вместо скалярных значений могут добавляться свойства сложных объектов:
const tom ={ name: "Tom", age: 22 } const tomInfo = `${tom.name} is ${tom.age} years old`; console.log(tomInfo); // Tom is 22 years old
Любо можно вставлять более сложные вычисляемые выражения:
function sum(x, y){ return x + y; } const a = 5; const b = 4; const result = `${a} + ${b} = ${sum(a, b)}`; console.log(result); // 5 + 4 = 9 const expression = `${a} * ${b} = ${ a * b}`; console.log(expression); // 5 * 4 = 20
В первом случае в шаблоне вызывается функция sum()
, параметрам которой передаются значения констант a
и
b
: ${sum(a, b)}
. В итоге в это место будет вставлена сумма a и b.
Во втором случае в шаблоне выполняется операция умножения констант: ${ a * b}
.
Шаблоны также могут хранить html-код, который будет динамически формироваться.
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>METANIT.COM</title> </head> <body> <script> const tom = {name: "Tom", age: 37}; const markup = `<div> <p><b>Name</b>: ${tom.name}</p> <p><b>Age</b>: ${tom.age}</p> </div>`; document.body.innerHTML = markup; </script> </body> </html>
Рассмотрим другой пример - создадим из элементов массива список html:
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>METANIT.COM</title> </head> <body> <script> const people = [{name: "Tom", age: 37}, {name:"Sam", age: 41}, {name: "Bob", age: 21}]; const markup = `<ul> ${people.map(person => `<li>${person.name}</li>`)} </ul>`; document.body.innerHTML = markup; </script> </body> </html>
В данном случае мы имеем дело с вложенным шаблоном. То есть вначале определяется общий внешний шаблон:
const markup = `<ul> ${.............} </ul>`;
А в динамически формируемом выражении применяется еще один шаблон:
${people.map(person => `<li>${person.name}</li>`)}
В данном случае у массива people вызывается функция map()
, которое определяет некоторое действие для каждого элемента массива. Это действие передается в
map()
в виде функции. Здесь для упрощения в качестве такой функции применяется лямбда-выражение. Оно получает каждый элемент массива
через параметр person
и для него формирует шаблон строки `<li>${person.name}</li>`
.
JavaScript позволяет передать в функцию шаблон строки, причем не просто как строку, но и все ее динамчески вычисляемые фрагменты в виде отдельных параметров. Для этого применяются тег-функции (tag function). Подобная возможность может применяться, например, для предобработки шаблонов и их значений. Рассмотрим следующий пример:
const person = "Tom"; function check (parts, name){ console.log(parts); return parts[0] + name + parts[1]; } const checkedTemplate = check`Person: ${person}.`; console.log(checkedTemplate);
Здесь определена tag-функция check()
, которая имеет два параметра: parts
и name
function check (parts, name){ console.log(parts); return parts[0] + name + parts[1]; }
Параметр parts
- это массив частей шаблона, разделенных вставляемыми динамическими фрагментами. Второй параметр - name
- это динамически
вычисляемый фрагмент шаблона. То есть в данном случае мы предполагаем, что шаблон строки, который передается в функцию check()
,
будет иметь только один динамчески вычисляемый фрагмент. Соответственно в массиве parts
будет два элемента: статическая часть шаблона, которая идет
до вычисляемого фрагмента, и часть шаблона, которая идет после.
Чтобы было более ясно, о чем идет речь, в функции выводим на консоль эти элементы массива parts.
Функция возвращает return parts[0] + name + parts[1]
, то есть по сути мы просто возвращаем ранее сформированный шаблон, ничего не меняя.
Обратите внимание, как мы передаем этой функции шаблон:
const checkedTemplate = check`Person: ${person}.`;
шаблон просто указывается после названия функции. Или иначе говоря, tag-функция указывается как префикс перед шаблоном.
Результат работы программы:
Array(2) 0: "Person: " 1: "." length: 2 raw: (2) ['Person: ', '.'] [[Prototype]]: Array(0) Person: Tom.
Из консольного вывода мы видим, что элементами массива parts являются подстроки "Person: " и ".". А в качестве значения параметра name
передается строка "Tom". Стоит отметить,
что даже если после динамически вычисляемого фрагмента больше не было бы никаких символов (например, `Person: ${person}`
), то массив
parts все равно имел бы два элемента, только вторым элементом тогда была бы пустая строка.
Но в примере выше мы просто возвращали то же содержимое, которое было сформировано на основе шаблона. Однако мы можем выполнить некоторую обработку:
const tom = "Tom"; const admin = "Admin"; function check (parts, name){ if(name === "Admin") return "Пользователь не определен"; else return parts[0] + name + parts[1]; } let checkedTemplate1 = check`Пользователь: ${tom}`; let checkedTemplate2 = check`Пользователь: ${admin}`; console.log(checkedTemplate1); console.log(checkedTemplate2);
В данном случае, если в шаблон передается значение "Admin", то возвращаем один результат, иначе возвращаем, то, что было бы сформированно на основе шаблона.
Пользователь: Tom Пользователь не определен
Подобным образом можно обрабатывать шаблоны с большим количеством вычисляемых фрагментов:
const tom = {name: "Tom", age: 37}; const bob = {name: "Bob", age: 11}; function check (parts, name, age){ if(age > 18) return `${parts[0]}${name}. Доступ открыт`; else return `Для пользователя ${name} доступ закрыт. Возраст ${age} недействителен`; } let checkedTemplate1 = check`Пользователь: ${tom.name} ${tom.age}`; let checkedTemplate2 = check`Пользователь: ${bob.name} ${bob.age}`; console.log(checkedTemplate1); console.log(checkedTemplate2);
В данном случае шаблон содержит два динамческих фрагмента. Соответственно в массива part будет три элемента.
В функции check()
в зависимости от значения второго динамического фрамегмента (условного возраста пользователя) возвращаем то или иное значение.
Консольный вывод:
Пользователь: Tom. Доступ открыт Для пользователя Bob доступ закрыт. Возраст 11 недействителен