Шаблоны строк
Шаблоны строк (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";
let 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;
}
let a = 5;
let b = 4;
const result = `${a} + ${b} = ${sum(a, b)}`;
console.log(result); // 5 + 4 = 9
let expression = `${a} * ${b} = ${ a * b}`;
console.log(expression); // 5 * 4 = 20
В первом случае в шаблоне вызывается функция sum()
, параметрам которой передаются значения переменных a
и b
: ${sum(a, b)}
. В итоге в это место будет вставлена сумма a
и b
. Во втором случае в шаблоне выполняется операция умножения переменных: ${ a * b}
.
html-код в шаблонах
Шаблоны также могут хранить 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 = `
${.............}
`;
А в динамически формируемом выражении применяется еще один шаблон:
${people.map(person => `<li>${person.name}</li>`)}
В данном случае у массива people
вызывается функция map()
, которая определяет некоторое действие для каждого элемента массива. Это действие передается в map()
в виде функции. Здесь для упрощения в качестве такой функции применяется лямбда-выражение. Оно получает каждый элемент массива через параметр person
и для него формирует шаблон строки `<li>${person.name}</li>`
.
Передача шаблона строки в функцию
JavaScript позволяет передать в функцию шаблон строки, причем не просто как строку, но и все ее динамчески вычисляемые фрагменты в виде отдельных параметров. Подобная возможность может применяться, например для предобработки шаблонов и их значений. Рассмотрим следующий пример:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>METANIT.COM</title>
</head>
<body>
<script>
const person = "Tom";
function check (parts, name){
console.log(parts);
return parts[0] + name + parts[1];
}
let checkedTemplate = check`Person: ${person}.`;
console.log(checkedTemplate);
document.body.innerHTML = checkedTemplate;
</script>
Здесь определена функция 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]
, то есть по сути мы просто возвращаем ранее сформированный шаблон ничего не меняя. Обратите внимание, как мы передаем этой функции шаблон, шаблон просто указывается после названия функции:
let checkedTemplate = check`Person: ${person}.`;
Из консольного вывода мы видим, что элементами массива 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
, то возвращаем один результат, иначе возвращаем что было бы сформированно на основе шаблона.
Подобным образом можно обрабатывать шаблоны с большим количеством вычисляемых фрагментов:
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 недействителен