Шаблоны строк
Шаблоны строк (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 недействителен