Шаблонні літерали - це рядкові літерали, які дозволяють використання вбудованих виразів. З ними ви можете використовувати багаторядковий запис та засоби інтерполяції рядків.
У попередніх версіях специфікації ES2015 вони називались "шаблонними рядками".
Синтаксис
`текстовий рядок` `текстовий рядок 1 текстовий рядок 2` `текст ${вираз} текст` тег`текст ${вираз} текст`
Опис
Шаблонні літерали заключаються у зворотні лапки (` `) (гравіс) замість подвійних чи одинарних лапок.
Шаблонні літерали можуть містити заповнювачі. Вони позначаються знаком долара та фігурними дужками (${вираз}
). Вирази у заповнювачах та текст між зворотними лапками (` `) передаються у функцію.
Проста функція просто з'єднує декілька частин у єдиний рядок. Якщо перед шаблоном знаходиться вираз (тег
), він називається тегованим шаблоном. У цьому випадку вираз тегу (зазвичай, це функція) викликається разом із шаблонним літералом, і ви можете маніпулювати ним перед поверненням.
Щоб екранувати зворотні лапки у шаблонному літералі, поставте зворотній слеш (\
) перед лапками.
`\`` === '`' // --> true
Багаторядковий запис
Будь-які символи нового рядка, вставлені у першокод, є частиною шаблонного літералу.
У звичайних рядках вам довелося б використати наступний синтаксис, щоб отримати багаторядковий запис:
console.log('текстовий рядок 1\n' +
'текстовий рядок 2');
// "текстовий рядок 1
// текстовий рядок 2"
У шаблонних літералах ви можете зробити те саме ось так:
console.log(`текстовий рядок 1
текстовий рядок 2`);
// "текстовий рядок 1
// текстовий рядок 2"
Інтерполяція виразів
Для того, щоб вставити вирази у звичайні рядки, ви б використали наступний синтаксис:
let a = 5;
let b = 10;
console.log('П\'ятнадцять - це ' + (a + b) + ', а\nне ' + (2 * a + b) + '.');
// "П'ятнадцять - це 15, а
// не 20."
Тепер, з шаблонними літералами, ви можете скористатись синтаксичним цукром, зробивши підстановки легшими для читання наступним чином:
let a = 5;
let b = 10;
console.log(`П'ятнадцять - це ${a + b}, а
не ${2 * a + b}.`);
// "П'ятнадцять - це 15, а
// не 20."
Вкладені шаблони
У певних випадках вкладений шаблон - це найкращий (і, мабуть, найлегший для читання) спосіб створювати рядки, що конфігуруються. Всередині шаблона у зворотних лапках легко створити внутрішні зворотні лапки, просто використавши їх всередині заповнювача ${ }
у шаблоні.
Наприклад, якщо умова a дорівнює true
, то повернути цей шаблонований літерал.
У ES5:
let 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'}` }`;
Теговані шаблони
Більш прогресивною формою шаблонних літералів є теговані шаблони.
Теги дозволяють розбирати шаблонні літерали за допомого функцій. Перший аргумент функції-тегу містить масив рядкових значень. Решта аргументів відносяться до виразів.
Далі функція-тег може виконати будь-які операції над цими аргументами та повернути отриманий рядок. (Як варіант, вона може повернути щось зовсім інше, як описано у одному з наступних прикладів.)
Ім'я функції, що використовується для тегу, може бути яким завгодно.
let person = 'Майк';
let age = 28;
function myTag(strings, personExp, ageExp) {
let str0 = strings[0]; // "Цей "
let str1 = strings[1]; // " - "
// Технічно, існує рядок після
// останнього виразу (в нашому прикладі),
// але він порожній (""), тому не зважаємо.
// let str2 = strings[2];
let ageStr;
if (ageExp > 99){
ageStr = 'довгожитель';
} else {
ageStr = 'юнак';
}
// Ми навіть можемо повернути рядок, побудований шаблонним літералом
return `${str0}${personExp}${str1}${ageStr}`;
}
let output = myTag`Цей ${ person } - ${ age }`;
console.log(output);
// Цей Майк - юнак
Функція-тег може навіть не повертати рядок!
function template(strings, ...keys) {
return (function(...values) {
let dict = values[values.length - 1] || {};
let result = [strings[0]];
keys.forEach(function(key, i) {
let value = Number.isInteger(key) ? values[key] : dict[key];
result.push(value, strings[i + 1]);
});
return result.join('');
});
}
let t1Closure = template`${0}${1}${0}!`;
t1Closure('Й', 'О'); // "ЙОЙ!"
let t2Closure = template`${0} ${'foo'}!`;
t2Closure('Всім', {foo: 'привіт'}); // "Всім привіт!"
Сирі рядки
Спеціальна властивість raw
, доступна на першому аргументі функції-тегу, дає доступ до сирих рядків у тому вигляді, як вони були записані, без обробки екранувань.
function tag(strings) {
console.log(strings.raw[0]);
}
tag`текстовий рядок 1 \n текстовий рядок 2`;
// виводить "текстовий рядок 1 \n текстовий рядок 2" ,
// в тому числі два символи, '\' та 'n'
На додачу, існує метод String.raw()
для створення сирих рядків — так само, як їх би створили проста шаблонна функція та об'єднання рядків.
let str = String.raw`Привіт\n${2+3}!`;
// "Привіт\n5!"
str.length;
// 10
Array.from(str).join(',');
// "П,р,и,в,і,т,\,n,5,!"
Теговані шаблони та екрановані послідовності
Поведінка в ES2016
У ECMAScript 2016 теговані шаблони відповідають правилам наступних екранованих послідовностей:
- Послідовності Юнікоду починаються з "
\u
", наприклад,\u00A9
- Екранування кодів символів Юнікоду позначаються через "
\u{}
", наприклад,\u{2F804}
- Шістнадцяткові послідовності починаються з "
\x
", наприклад,\xA9
- Вісімкові літеральні послідовності починаються з "
\0o
", далі йде одна чи більше цифр, наприклад,\0o251
Це означає, що тегований шаблон, наведений нижче, є проблематичним, оскільки, згідно з граматикою ECMAScript, синтаксичний аналізатор шукає коректну екрановану послідовність Юнікоду, але знаходить неправильно сформований синтаксис:
latex`\unicode`
// Викидає помилку у старших версіях ECMAScript (ES2016 та старші)
// SyntaxError: malformed Unicode character escape sequence
Перегляд недозволених екранованих послідовностей у ES2018
Теговані шаблони повинні дозволяти вкладені мови (наприклад, DSL чи LaTeX), де існують інші екрановані послідовності. Пропозиція ECMAScript Template Literal Revision (Стадія 4, має бути інтегрована у стандарт ECMAScript 2018) прибирає обмеження синтаксису екранованих послідовностей ECMAScript з тегованих шаблонів.
Однак, недозволені екрановані послідовності все одно мають бути представлені у “готовому” представленні. Вони з'являться як елемент undefined
у масиві “cooked” (готовий):
function latex(str) {
return { "cooked": str[0], "raw": str.raw[0] }
}
latex`\unicode`
// { cooked: undefined, raw: "\\unicode" }
Зауважте, що обмеження екранованих послідовностей прибираються лише з тегованих шаблонів, вони не прибираються з нетегованих шаблонних літералів:
let bad = `погана екранована послідовність: \unicode`;
Специфікації
Специфікація |
---|
ECMAScript (ECMA-262) The definition of 'Template Literals' in that specification. |
ECMAScript (ECMA-262) The definition of 'Tagged templates Literals' in that specification. |
Сумісність з веб-переглядачами
BCD tables only load in the browser