aboutsummaryrefslogtreecommitdiff
path: root/files/ru/web/javascript/reference/template_strings/index.html
blob: d8b4b9a442d28d5dcd2a964c8191ee5210598ed7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
---
title: Шаблонные строки
slug: Web/JavaScript/Reference/template_strings
tags:
  - ECMAScript6
  - JavaScript
  - Строки
  - Шаблонные строки
  - Экспериментальный
translation_of: Web/JavaScript/Reference/Template_literals
---
<div>{{JsSidebar("More")}}</div>

<div>Шаблонными литералами называются строковые литералы, допускающие использование выражений внутри. С ними вы можете использовать многострочные литералы и строковую интерполяцию. В спецификациях до ES2015 они назывались "шаблонными строками".</div>

<h2 id="Syntax" name="Syntax">Синтаксис</h2>

<pre class="syntaxbox">`строка текста`

`строка текста 1
 строка текста 2`

`строка текста ${выражение} строка текста`

tag `строка текста ${выражение} строка текста`
</pre>

<h2 id="Description" name="Description">Описание</h2>

<p>Шаблонные литералы заключены в обратные кавычки (` `) вместо двойных или одинарных. Они могут содержать подстановки, обозначаемые знаком доллара и фигурными скобками (<code>${выражение}</code>). Выражения в подстановках и текст между ними передаются в функцию. По умолчанию функция просто объединяет все части в строку. Если перед строкой есть выражение (здесь это <code>tag</code>), то шаблонная строка называется "теговым шаблоном". В этом случае, теговое выражение (обычно функция) вызывается с обработанным шаблонным литералом, который вы можете изменить перед выводом. Для экранирования обратной кавычки в шаблонных литералах указывается обратный слэш <strong>\</strong>.</p>

<pre class="brush: js">`\`` === '`' // --&gt; true</pre>

<h3 id="Многострочные_литералы">Многострочные литералы</h3>

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

<pre class="brush: js">console.log('string text line 1\n' +
'string text line 2');
// "string text line 1
//  string text line 2"</pre>

<p>То же с использованием шаблонных литералов:</p>

<pre class="brush: js">console.log(`string text line 1
string text line 2`);
// "string text line 1
//  string text line 2"</pre>

<h3 id="Интерполяция_выражений">Интерполяция выражений</h3>

<p>Для вставки выражений в обычные строки вам пришлось бы использовать следующий синтаксис:</p>

<pre class="brush: js">var a = 5;
var b = 10;
console.log('Fifteen is ' + (a + b) + ' and not ' + (2 * a + b) + '.');
// "Fifteen is 15 and not 20."</pre>

<p>Теперь, при помощи шаблонных литералов, вам доступен "синтаксический сахар", делающий подстановки вроде той более читабельными:</p>

<pre class="brush: js">var a = 5;
var b = 10;
console.log(`Fifteen is ${a + b} and not ${2 * a + b}.`);
// "Fifteen is 15 and not 20."</pre>

<h3 id="Вложенные_шаблоны">Вложенные шаблоны</h3>

<p>Временами, вложить шаблон — это кратчайший и, возможно, более читабельный способ составить строку. Просто поместите внутрь шаблона с обратными кавычками ещё одни, обернув их в подстановку <code>${ }</code>. Например, если выражение истинно, можно вернуть шаблонный литерал.</p>

<p>В ES5:</p>

<pre class="brush: js">var classes = 'header'
classes += (isLargeScreen() ?
   '' : item.isCollapsed ?
     ' icon-expander' : ' icon-collapser');</pre>

<p>В ES2015 с шаблонными литералами без вложения:</p>

<pre class="brush: js">const classes = `header ${ isLargeScreen() ? '' :
    (item.isCollapsed ? 'icon-expander' : 'icon-collapser') }`;
</pre>

<p>В ES2015 с вложенными шаблонными литералами:</p>

<pre class="brush: js">const classes = `header ${ isLargeScreen() ? '' :
`icon-${item.isCollapsed ? 'expander' : 'collapser'}` }`;
</pre>

<h3 id="Теговые_шаблоны">Теговые шаблоны</h3>

<p>Расширенной формой шаблонных литералов являются <em>теговые</em> шаблоны. Они позволяют разбирать шаблонные литералы с помощью функции. Первый аргумент такой функции содержит массив строковых значений, а остальные содержат выражения из подстановок. В итоге, функция должна вернуть собранную строку (или что-либо совсем иное, как будет показано далее). Имя функции может быть любым.</p>

<pre class="brush: js">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 &gt; 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</pre>

<p>Функция тега не обязана возвращать строку, как показано в примере ниже:</p>

<pre class="brush: js">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!"
</pre>

<h3 id="Сырые_строки">Сырые строки</h3>

<p>Специальное свойство <code>raw</code>, доступное для первого аргумента тегового шаблона, позволяет получить строку в том виде, в каком она была введена, без <a href="/ru/docs/Web/JavaScript/Guide/Grammar_and_types#Использование_специальных_символов_в_строках">экранирования</a>.</p>

<pre class="brush: js">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' и два символа '\'
</pre>

<p>Вдобавок, существует метод {{jsxref('String.raw()')}}, возвращающий точно такую же исходную строку, какую вернула бы функция шаблона по умолчанию и строковая конкатенация вместе.</p>

<pre class="brush: js">var str = String.raw`Hi\n${2+3}!`;
// "Hi\n5!"

str.length;
// 6

str.split('').join(',');
// "H,i,\,n,5,!"</pre>

<h3 id="Теговые_шаблоны_и_экранирование_символов">Теговые шаблоны и экранирование символов</h3>

<h4 id="Поведение_в_ES2016">Поведение в ES2016</h4>

<p>В ECMAScript 2016 теговые шаблоны следуют правилам экранирования следующих символов:</p>

<ul>
 <li>символы Unicode, начинающиеся с "\u", например, <code>\u00A9</code></li>
 <li>точки кода Unicode, начинающиеся с "\u{}", например, <code>\u{2F804}</code></li>
 <li>шестнадцатеричные представления символов, начинающиеся с "\x", например, <code>\xA9</code></li>
 <li>восьмеричные представления символов, начинающиеся с "\", например, <code>\251</code>​​​​​​</li>
</ul>

<p>Отсюда вытекает проблема теговых шаблонов: следуя грамматике ECMAScript, анализатор кода, найдя символ <code>\</code>, будет искать корректное представление символа Unicode, но может не найти его вовсе. Пример ниже показывает это:</p>

<pre class="brush: js">latex`\unicode`
// В старых версиях ECMAScript (ES2016 и раньше) выкинет исключение:
// SyntaxError: malformed Unicode character escape sequence</pre>

<h4 id="Поведение_в_ES2018">Поведение в ES2018</h4>

<p>Теговые шаблоны должны позволять встраивать языки (например, <a href="https://ru.wikipedia.org/wiki/%D0%9F%D1%80%D0%B5%D0%B4%D0%BC%D0%B5%D1%82%D0%BD%D0%BE-%D0%BE%D1%80%D0%B8%D0%B5%D0%BD%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%BD%D1%8B%D0%B9_%D1%8F%D0%B7%D1%8B%D0%BA">DSLs</a> или <a href="https://ru.wikipedia.org/wiki/LaTeX">LaTeX</a>), в которых широко используются многие другие экранирования. Предложение <a href="https://tc39.github.io/proposal-template-literal-revision/">Редакция шаблонных литералов</a> (уровень 4, одобренный к добавлению в стандарт ECMAScript 2018) устраняет синтаксические ограничения экранирования теговых шаблонов в ECMAScript.</p>

<p>Однако, некорректное экранирование символов по-прежнему нужно отображать в "приготовленном" отображении. Оно показывается в виде {{jsxref("undefined")}} в "приготовленном" массиве:</p>

<pre class="brush: js">function latex(str) {
 return { "cooked": str[0], "raw": str.raw[0] }
}

latex`\unicode`

// { cooked: undefined, raw: "\unicode" }</pre>

<p>Заметьте, что ограничение на экранирование символов проявляется лишь в <em>теговых</em> шаблонах, и не проявляется в <em>нетеговых</em> шаблонных литералах:</p>

<pre class="brush: js example-bad">let bad = `bad escape sequence: \unicode`;</pre>

<h2 id="Спецификации">Спецификации</h2>

<table class="standard-table">
 <tbody>
  <tr>
   <th scope="col">Спецификация</th>
   <th scope="col">Статус</th>
   <th scope="col">Комментарий</th>
  </tr>
  <tr>
   <td>{{SpecName('ES2015', '#sec-template-literals', 'Template Literals')}}</td>
   <td>{{Spec2('ES2015')}}</td>
   <td>Изначальное определение. Определено в секциях <a href="http://www.ecma-international.org/ecma-262/6.0/#sec-template-literals">Template Literals</a>, <a href="http://www.ecma-international.org/ecma-262/6.0/#sec-tagged-templates">Tagged Templates</a></td>
  </tr>
  <tr>
   <td>{{SpecName('ESDraft', '#sec-template-literals', 'Template Literals')}}</td>
   <td>{{Spec2('ESDraft')}}</td>
   <td>Определено в секциях <a href="https://tc39.github.io/ecma262/#sec-template-literals">Template Literals</a>, <a href="https://tc39.github.io/ecma262/#sec-tagged-templates">Tagged Templates</a></td>
  </tr>
  <tr>
   <td><a href="https://tc39.github.io/proposal-template-literal-revision/">Template Literal Revision</a></td>
   <td>Черновик 4-го уровня</td>
   <td>Устранено ограничение экранирования в теговых шаблонах</td>
  </tr>
 </tbody>
</table>

<h2 id="Совместимость_с_браузерами">Совместимость с браузерами</h2>

<div class="hidden">Таблица совместимости на этой странице сгенерирована из автоматически получаемых данных. Если вы хотите внести свои данные, пожалуйста перейдите на <a href="https://github.com/mdn/browser-compat-data">https://github.com/mdn/browser-compat-data</a> и отправьте нам пул-реквест.</div>

<p>{{Compat("javascript.grammar.template_literals")}}</p>

<h2 id="Смотрите_также">Смотрите также</h2>

<ul>
 <li>{{jsxref("String")}}</li>
 <li>{{jsxref("String.raw()")}}</li>
 <li><a href="/en-US/docs/Web/JavaScript/Reference/Lexical_grammar">Лексическая грамматика</a></li>
 <li><a href="https://gist.github.com/WebReflection/8f227532143e63649804">Подобные шаблонам строки в ES3-совместимом синтаксисе</a></li>
 <li><a href="https://hacks.mozilla.org/2015/05/es6-in-depth-template-strings-2/">ES6 в деталях: шаблонные строки</a></li>
</ul>