Шаблонные строки
Шаблонными литералами называются строковые литералы, допускающие использование выражений внутри. С ними вы можете использовать многострочные литералы и строковую интерполяцию. В спецификациях до ES2015 они назывались "шаблонными строками".
Синтаксис
`строка текста` `строка текста 1 строка текста 2` `строка текста ${выражение} строка текста` tag `строка текста ${выражение} строка текста`
Описание
Шаблонные литералы заключены в обратные кавычки (` `) вместо двойных или одинарных. Они могут содержать подстановки, обозначаемые знаком доллара и фигурными скобками (${выражение}
). Выражения в подстановках и текст между ними передаются в функцию. По умолчанию функция просто объединяет все части в строку. Если перед строкой есть выражение (здесь это tag
), то шаблонная строка называется "теговым шаблоном". В этом случае, теговое выражение (обычно функция) вызывается с обработанным шаблонным литералом, который вы можете изменить перед выводом. Для экранирования обратной кавычки в шаблонных литералах указывается обратный слеш \.
`\`` === "`"; // --> true
Многострочные литералы
Символы новой строки являются частью шаблонных литералов. Используя обычные строки, вставка переноса потребовала бы следующего синтаксиса:
console.log("string text line 1\n" + "string text line 2");
// "string text line 1
// string text line 2"
То же с использованием шаблонных литералов:
console.log(`string text line 1
string text line 2`);
// "string text line 1
// string text line 2"
Интерполяция выражений
Для вставки выражений в обычные строки вам пришлось бы использовать следующий синтаксис:
var a = 5;
var b = 10;
console.log("Fifteen is " + (a + b) + " and not " + (2 * a + b) + ".");
// "Fifteen is 15 and not 20."
Теперь, при помощи шаблонных литералов, вам доступен "синтаксический сахар", делающий подстановки вроде той более читабельными:
var a = 5;
var b = 10;
console.log(`Fifteen is ${a + b} and not ${2 * a + b}.`);
// "Fifteen is 15 and not 20."
Вложенные шаблоны
Временами, вложить шаблон — это кратчайший и, возможно, более читабельный способ составить строку. Просто поместите внутрь шаблона с обратными кавычками ещё одни, обернув их в подстановку ${ }
. Например, если выражение истинно, можно вернуть шаблонный литерал.
В ES5:
var classes = "header";
classes += isLargeScreen()
? ""
: item.isCollapsed
? " icon-expander"
: " icon-collapser";
В ES2015 с шаблонными литералами без вложения:
const classes = `header ${
isLargeScreen() ? "" : item.isCollapsed ? "icon-expander" : "icon-collapser"
}`;
В ES2015 с вложенными шаблонными литералами:
const classes = `header ${
isLargeScreen() ? "" : `icon-${item.isCollapsed ? "expander" : "collapser"}`
}`;
Теговые шаблоны
Расширенной формой шаблонных литералов являются теговые шаблоны. Они позволяют разбирать шаблонные литералы с помощью функции. Первый аргумент такой функции содержит массив строковых значений, а остальные содержат выражения из подстановок. В итоге, функция должна вернуть собранную строку (или что-либо совсем иное, как будет показано далее). Имя функции может быть любым.
var person = "Mike";
var age = 28;
function myTag(strings, personExp, ageExp) {
var str0 = strings[0]; // "That "
var str1 = strings[1]; // " is a "
// Технически, в конце итогового выражения
// (в нашем примере) есть ещё одна строка,
// но она пустая (""), так что пропустим её.
// var str2 = strings[2];
var ageStr;
if (ageExp > 99) {
ageStr = "centenarian";
} else {
ageStr = "youngster";
}
// Мы даже можем вернуть строку, построенную другим шаблонным литералом
return `${str0}${personExp}${str1}${ageStr}`;
}
var output = myTag`That ${person} is a ${age}`;
console.log(output);
// That Mike is a youngster
Функция тега не обязана возвращать строку, как показано в примере ниже:
function template(strings, ...keys) {
return function (...values) {
var dict = values[values.length - 1] || {};
var result = [strings[0]];
keys.forEach(function (key, i) {
var value = Number.isInteger(key) ? values[key] : dict[key];
result.push(value, strings[i + 1]);
});
return result.join("");
};
}
var t1Closure = template`${0}${1}${0}!`;
t1Closure("Y", "A"); // "YAY!"
var t2Closure = template`${0} ${"foo"}!`;
t2Closure("Hello", { foo: "World" }); // "Hello World!"
Сырые строки
Специальное свойство raw
, доступное для первого аргумента тегового шаблона, позволяет получить строку в том виде, в каком она была введена, без экранирования.
function tag(strings) {
return strings.raw[0];
}
tag`string text line 1 \\n string text line 2`;
// выводит "string text line 1 \\n string text line 2",
// включая 'n' и два символа '\'
Вдобавок, существует метод String.raw()
, возвращающий точно такую же исходную строку, какую вернула бы функция шаблона по умолчанию и строковая конкатенация вместе.
var str = String.raw`Hi\n${2 + 3}!`;
// "Hi\n5!"
str.length;
// 6
str.split("").join(",");
// "H,i,\,n,5,!"
Теговые шаблоны и экранирование символов
Поведение в ES2016
В ECMAScript 2016 теговые шаблоны следуют правилам экранирования следующих символов:
- символы Unicode, начинающиеся с "\u", например,
\u00A9
- точки кода Unicode, начинающиеся с "\u{}", например,
\u{2F804}
- шестнадцатеричные представления символов, начинающиеся с "\x", например,
\xA9
- восьмеричные представления символов, начинающиеся с "\", например,
\251
Отсюда вытекает проблема теговых шаблонов: следуя грамматике ECMAScript, анализатор кода, найдя символ \
, будет искать корректное представление символа Unicode, но может не найти его вовсе. Пример ниже показывает это:
latex`\unicode`;
// В старых версиях ECMAScript (ES2016 и раньше) выкинет исключение:
// SyntaxError: malformed Unicode character escape sequence
Поведение в ES2018
Теговые шаблоны должны позволять встраивать языки (например, DSLs или LaTeX), в которых широко используются многие другие экранирования. Предложение Редакция шаблонных литералов (уровень 4, одобренный к добавлению в стандарт ECMAScript 2018) устраняет синтаксические ограничения экранирования теговых шаблонов в ECMAScript.
Однако, некорректное экранирование символов по-прежнему нужно отображать в "приготовленном" отображении. Оно показывается в виде undefined
в "приготовленном" массиве:
function latex(str) {
return { cooked: str[0], raw: str.raw[0] };
}
latex`\unicode`;
// { cooked: undefined, raw: "\unicode" }
Заметьте, что ограничение на экранирование символов проявляется лишь в теговых шаблонах, и не проявляется в нетеговых шаблонных литералах:
let bad = `bad escape sequence: \unicode`;
Спецификации
Specification |
---|
ECMAScript Language Specification # sec-template-literals |
Совместимость с браузерами
BCD tables only load in the browser