Spec-Zone.ru › JavaScript

Шаблонные литералы (Шаблонные строки)

Базовый уровень Широко доступно

Эта функция хорошо зарекомендовала себя и работает на многих устройствах и версиях браузеров. Она доступна во всех браузерах с января 2020 года.

Шаблонные литералы — это литералы, заключенные в символы обратного апострофа (`), позволяющие использовать многострочные строки, интерполяцию строк с внедренными выражениями и специальные конструкции, называемые тегированными шаблонами.

Шаблонные литералы иногда неформально называют шаблонными строками, поскольку они чаще всего используются для интерполяции строк (для создания строк путем подстановки заполнителей). Однако тегированный шаблонный литерал может не возвращать строку; он может использоваться с пользовательской тег-функцией для выполнения любых операций, которые вы хотите над различными частями шаблонного литерала.

Синтаксис

`string text`

`string text line 1
 string text line 2`

`string text ${expression} string text`

tagFunction`string text ${expression} string text`

Параметры

string text
Текст строки, который станет частью шаблонного литерала. Почти все символы разрешены как есть, включая символы новой строки и другие пробельные символы. Однако недопустимые управляющие последовательности вызовут ошибку синтаксиса, если не используется тег-функция.
expression
Выражение для вставки в текущую позицию, значение которого преобразуется в строку или передается в tagFunction.
tagFunction
Если указана, она будет вызвана с массивом строк шаблона и выражениями подстановки, а возвращаемое значение станет значением шаблонного литерала. См. тегированные шаблоны.

Описание

Шаблонные литералы заключаются в символы обратного апострофа (`) вместо двойных или одинарных кавычек.

Помимо обычных строк, шаблонные литералы могут содержать другие части, называемые заполнителями, которые представляют собой внедренные выражения, заключенные в знак доллара и фигурные скобки: ${expression}. Строки и заполнители передаются функции — либо функции по умолчанию, либо функции, которую вы предоставите. Функция по умолчанию (когда вы не предоставляете свою) просто выполняет интерполяцию строк для подстановки заполнителей, а затем объединяет части в одну строку.

Чтобы предоставить свою функцию, предшествуйте шаблонному литералу именем функции; результат называется тегированным шаблоном. В этом случае шаблонный литерал передается вашей тег-функции, где вы можете затем выполнять любые операции, которые вы хотите, над различными частями шаблонного литерала.

Чтобы экранировать обратный апостроф в шаблонном литерале, поставьте обратную косую черту (\) перед обратным апострофом.

`\`` === "`"; // true

Знаки доллара также можно экранировать, чтобы предотвратить интерполяцию.

`\${1}` === "${1}"; // true

Многострочные строки

Любые символы новой строки, вставленные в исходный код, являются частью шаблонного литерала.

Используя обычные строки, вам пришлось бы использовать следующий синтаксис для получения многострочных строк:

console.log("string text line 1\nstring 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"

Как и обычные строковые литералы, вы можете записать однострочную строку в нескольких строках для читаемости исходного кода, экранировав новую строку обратной косой чертой (\):

console.log(`string text line 1 \
string text line 2`);
// "string text line 1 string text line 2"

Интерполяция строк

Без шаблонных литералов, когда вы хотите объединить вывод выражений со строками, вы бы объединяли их с помощью оператора сложения +:

const a = 5;
const b = 10;
console.log("Fifteen is " + (a + b) + " and\nnot " + (2 * a + b) + ".");
// "Fifteen is 15 and
// not 20."

Это может быть трудно читать — особенно когда у вас есть несколько выражений.

С шаблонными литералами вы можете избежать оператора конкатенации — и улучшить читаемость вашего кода — используя заполнители в форме ${expression} для выполнения подстановок для встроенных выражений:

const a = 5;
const b = 10;
console.log(`Fifteen is ${a + b} and
not ${2 * a + b}.`);
// "Fifteen is 15 and
// not 20."

Обратите внимание, что между двумя синтаксисами есть небольшое различие. Шаблонные литералы приводят свои выражения непосредственно к строкам, в то время как сложение сначала приводит свои операнды к примитивам. Дополнительную информацию см. на странице справки по оператору +.

Вложенные шаблоны

В некоторых случаях вложенный шаблон является самым простым (и, возможно, более читаемым) способом создания настраиваемых строк. Внутри шаблона, ограниченного обратными апострофами, легко использовать внутренние обратные апострофы, используя их внутри плейсхолдера ${expression} в шаблоне.

Например, без шаблонных литералов, если бы вы хотели вернуть определенное значение на основе конкретного условия, вы могли бы сделать что-то вроде следующего:

let classes = "header";
classes += isLargeScreen()
  ? ""
  : item.isCollapsed
    ? " icon-expander"
    : " icon-collapser";

С шаблонным литералом, но без вложения, вы могли бы сделать это:

const classes = `header ${
  isLargeScreen() ? "" : item.isCollapsed ? "icon-expander" : "icon-collapser"
}`;

С вложением шаблонных литералов вы можете сделать это:

const classes = `header ${
  isLargeScreen() ? "" : `icon-${item.isCollapsed ? "expander" : "collapser"}`
}`;

Тегированные шаблоны

Более продвинутой формой шаблонных литералов являются тегированные шаблоны.

Теги позволяют парсить шаблонные литералы с помощью функции. Первый аргумент тег-функции содержит массив строковых значений. Остальные аргументы относятся к выражениям.

Затем тег-функция может выполнять любые операции над этими аргументами по вашему желанию и возвращать измененную строку. (Альтернативно, она может возвращать что-то совершенно другое, как описано в одном из следующих примеров.)

Имя функции, используемой для тега, может быть любым, каким вы хотите.

const person = "Mike";
const age = 28;

function myTag(strings, personExp, ageExp) {
  const str0 = strings[0]; // "That "
  const str1 = strings[1]; // " is a "
  const str2 = strings[2]; // "."

  const ageStr = ageExp < 100 ? "youngster" : "centenarian";

  // We can even return a string built using a template literal
  return `${str0}${personExp}${str1}${ageStr}${str2}`;
}

const output = myTag`That ${person} is a ${age}.`;

console.log(output);
// That Mike is a youngster.

Тег не обязательно должен быть простым идентификатором. Вы можете использовать любое выражение с приоритетом выше 16, что включает доступ к свойствам, вызов функции, создание объекта через new или даже другой тегированный шаблонный литерал.

console.log`Hello`; // [ 'Hello' ]
console.log.bind(1, 2)`Hello`; // 2 [ 'Hello' ]
new Function("console.log(arguments)")`Hello`; // [Arguments] { '0': [ 'Hello' ] }

function recursive(strings, ...values) {
  console.log(strings, values);
  return recursive;
}
recursive`Hello``World`;
// [ 'Hello' ] []
// [ 'World' ] []

Хотя технически разрешено синтаксисом, не тегированные шаблонные литералы являются строками и вызовут TypeError при цепочке.

console.log(`Hello``World`); // TypeError: "Hello" is not a function

Единственным исключением является опциональная цепочка, которая вызовет ошибку синтаксиса.

console.log?.`Hello`; // SyntaxError: Invalid tagged template on optional chain
console?.log`Hello`; // SyntaxError: Invalid tagged template on optional chain

Обратите внимание, что эти два выражения все еще парсятся. Это означает, что они не будут подвержены автоматической вставке точек с запятой, которая вставляет точки с запятой только для исправления кода, который иначе не может быть разобран.

// Still a syntax error
const a = console?.log
`Hello`

Тег-функции даже не обязательно возвращать строку!

function template(strings, ...keys) {
  return (...values) => {
    const dict = values[values.length - 1] || {};
    const result = [strings[0]];
    keys.forEach((key, i) => {
      const value = Number.isInteger(key) ? values[key] : dict[key];
      result.push(value, strings[i + 1]);
    });
    return result.join("");
  };
}

const t1Closure = template`${0}${1}${0}!`;
// const t1Closure = template(["","","","!"],0,1,0);
t1Closure("Y", "A"); // "YAY!"

const t2Closure = template`${0} ${"foo"}!`;
// const t2Closure = template([""," ","!"],0,"foo");
t2Closure("Hello", { foo: "World" }); // "Hello World!"

const t3Closure = template`I'm ${"name"}. I'm almost ${"age"} years old.`;
// const t3Closure = template(["I'm ", ". I'm almost ", " years old."], "name", "age");
t3Closure("foo", { name: "MDN", age: 30 }); // "I'm MDN. I'm almost 30 years old."
t3Closure({ name: "MDN", age: 30 }); // "I'm MDN. I'm almost 30 years old."

Первый аргумент, полученный тег-функцией, — это массив строк. Для любого шаблонного литерала его длина равна количеству подстановок (вхождений ${…}) плюс один, и поэтому он всегда не пуст.

Для любого конкретного выражения тегированного шаблонного литерала тег-функция всегда будет вызвана с тем же самым массивом литерала, независимо от того, сколько раз литерал будет вычислен.

const callHistory = [];

function tag(strings, ...values) {
  callHistory.push(strings);
  // Return a freshly made object
  return {};
}

function evaluateLiteral() {
  return tag`Hello, ${"world"}!`;
}

console.log(evaluateLiteral() === evaluateLiteral()); // false; each time `tag` is called, it returns a new object
console.log(callHistory[0] === callHistory[1]); // true; all evaluations of the same tagged literal would pass in the same strings array

Это позволяет тегу кэшировать результат на основе идентификатора своего первого аргумента. Для дальнейшего обеспечения стабильности значения массива, первый аргумент и его свойство raw оба заморожены, так что вы не можете их изменить каким-либо образом.

Сырые строки

Специальное свойство raw, доступное в первом аргументе тег-функции, позволяет получить доступ к сырым строкам в том виде, в котором они были введены, без обработки управляющих последовательностей.

function tag(strings) {
  console.log(strings.raw[0]);
}

tag`string text line 1 \n string text line 2`;
// Logs "string text line 1 \n string text line 2",
// including the two characters '\' and 'n'

Примечание: Синтаксис шаблонных литералов по-прежнему обрабатывается таким же образом, что означает, что неэкранированные обратные апострофы и ${ имеют специальное синтаксическое значение, но экранирование этих символов создает дополнительные обратные косые черты в сырой строке. См. сырые строки, содержащие синтаксис шаблонных литералов для получения дополнительной информации.

Кроме того, существует метод String.raw() для создания сырых строк точно так же, как это сделал бы функция шаблона по умолчанию и конкатенация строк.

const str = String.raw`Hi\n${2 + 3}!`;
// "Hi\\n5!"

str.length;
// 6

Array.from(str).join(",");
// "H,i,\\,n,5,!"

String.raw действует как "идентичная" тег-функция, если литерал не содержит управляющих последовательностей. В случае, если вам нужна настоящая идентичная тег-функция, которая всегда работает так, как если бы литерал был не тегированным, вы можете создать пользовательскую функцию, которая передает "обработанный" (т.е. управляющие последовательности обработаны) массив литералов в String.raw, представляя их как сырые строки.

const identity = (strings, ...values) =>
  String.raw({ raw: strings }, ...values);
console.log(identity`Hi\n${2 + 3}!`);
// Hi
// 5!

Это полезно для многих инструментов, которые уделяют особое внимание литералам, тегированным определенным именем.

const html = (strings, ...values) => String.raw({ raw: strings }, ...values);
// Some formatters will format this literal's content as HTML
const doc = html`<!doctype html>
  <html lang="en-US">
    <head>
      <title>Hello</title>
    </head>
    <body>
      <h1>Hello world!</h1>
    </body>
  </html>`;

Тегированные шаблоны и управляющие последовательности

В обычных шаблонных литералах управляющие последовательности в строковых литералах допускаются. Любая другая некорректная управляющая последовательность является синтаксической ошибкой. Это включает:

  • \ за которой следует любая десятичная цифра, кроме 0, или \0 за которой следует десятичная цифра; например \9 и \07 (что является устаревшим синтаксисом)
  • \x за которой следует менее двух шестнадцатеричных цифр (включая ноль); например \xz
  • \u не за которым следует {, и за которым следует менее четырех шестнадцатеричных цифр (включая ноль); например \uz
  • \u{}, заключающий недопустимую кодовую точку Unicode — содержит недопустимую шестнадцатеричную цифру или его значение больше 10FFFF; например \u{110000} и \u{z}

Примечание: \, за которым следуют другие символы, хотя они могут быть бесполезны, поскольку ничего не экранировано, не являются синтаксическими ошибками.

Однако это проблематично для тегированных шаблонов, которые, помимо "обработанного" литерала, также имеют доступ к сырым литералам (управляющие последовательности сохраняются как есть).

Тегированные шаблоны позволяют встраивать произвольный строковый контент, где управляющие последовательности могут следовать другому синтаксису. Рассмотрим, например, случай, когда мы встраиваем LaTeX исходный текст в JavaScript через String.raw. Мы хотим по-прежнему иметь возможность использовать макросы LaTeX, которые начинаются с u или x, не следуя ограничениям синтаксиса JavaScript. Поэтому ограничение синтаксиса корректных управляющих последовательностей снято с тегированных шаблонов. Пример ниже использует MathJax для рендеринга LaTeX в одном элементе:

const node = document.getElementById("formula");
MathJax.typesetClear([node]);
// Throws in older ECMAScript versions (ES2016 and earlier)
// SyntaxError: malformed Unicode character escape sequence
node.textContent = String.raw`$\underline{u}$`;
MathJax.typesetPromise([node]);

Однако недопустимые управляющие последовательности все равно должны быть представлены в "обработанном" представлении. Они будут отображаться как элемент undefined в "обработанном" массиве:

function log(str) {
  console.log("Cooked:", str[0]);
  console.log("Raw:", str.raw[0]);
}

log`\unicode`;
// Cooked: undefined
// Raw: \unicode

Обратите внимание, что ограничение на управляющие последовательности снято только с тегированных шаблонов, но не с не тегированных шаблонных литералов:

const bad = `bad escape sequence: \unicode`;

Спецификации

Спецификация
Спецификация языка ECMAScript® 2027
# sec-template-literals

Совместимость с браузерами

Десктоп Мобильный Сервер
Chrome Edge Firefox Opera Safari Chrome Android Firefox for Android Opera Android Safari on iOS Samsung Internet WebView Android WebView on iOS Bun Deno Node.js
template_literals
41
12
34
28
9
41
34
28
9
4.0
41
9
1.0.0
1.0
4.0.0
template_literal_revision
62
79
53
49
11
62
53
46
11
8.0
62
11
1.1.35
1.0
8.10.0

См. также

  • Руководство по числам и строкам
  • String
  • String.raw()
  • Лексическая грамматика
  • ES6 в деталях: Шаблонные строки на hacks.mozilla.org (2015)

© 2005–2025 MDN contributors.
Licensed under the Creative Commons Attribution-ShareAlike License v2.5 or later.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API