Как тегированные литералы шаблона работают в JavaScript?

Рассмотрим следующий фрагмент:

let a = (x) => console.log(x);
a`1234`; // prints "Array [ "1234" ]"

Почему строка, следующая за переменной, содержащей анонимную функцию, заставляет функцию выполняться, передавая себя в массив в качестве аргумента? Есть ли ссылка на документацию для этого поведения?

Кроме того, почему это не работает при использовании кавычек или двойных кавычек для объявления строкового литерала?


person Roger    schedule 18.02.2019    source источник
comment
Вы знакомы с параметрами тегированного литерала шаблона?   -  person jhpratt    schedule 18.02.2019
comment
Никогда раньше не слышал об этой концепции, просто проверил документацию, спасибо @jhpratt!   -  person Roger    schedule 18.02.2019
comment
Только что обновил свой ответ. Надеюсь, он дает небольшое введение в тегированные литералы шаблонов, учитывая, что их не так уж и много!   -  person jhpratt    schedule 19.02.2019


Ответы (1)


Теги шаблонных литералов принимают форму (strings: string[], ...values: any[]): any .

В вашем примере

let a = (x) => console.log(x);
a`1234`; // prints "Array [ "1234" ]"

x имеет тип string[], который представляет собой массив всех неинтерполированных строк (в основном все, что не находится внутри ${}). Поскольку интерполяции нет, массив содержит один элемент (строку «1234»). Это то, что передается в качестве первого аргумента вашей функции a.

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

Если вы хотите интерполировать значение, вы должны сделать это, получив значение в функции (которая используется в качестве тега) путем добавления дополнительных параметров. Обратите внимание, что это не отдельный параметр, который является массивом, а, скорее, отдельные параметры. Вы, конечно, можете создать из них массив, используя оператор распространения (...), как указано в сигнатуре функции выше. Как и в (измененном) примере, предоставленном MDN,

const person = 'Mike';
const age = 28;

function tag(strings, person, age) {
  const str0 = strings[0]; // "That "
  const str1 = strings[1]; // " is a "

  // There is technically a string after
  // the final expression (in our example),
  // but it is empty (""), so disregard.
  // const str2 = strings[2];

  const age_description = age > 99 ? 'centenarian' : 'youngster';
  return [str0, name, str1, ageDescription].join('');
}

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

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

Обратите внимание, что, как указано в комментариях, есть всегда начальная и конечная строка, даже если она оказывается пустой. Таким образом, если вы начали литерал шаблона с интерполяции, strings[0] будет пустой строкой. Таким же образом, завершение интерполяцией оставляет завершающую пустую строку, хотя это не так заметно (ведущая интерполяция сдвигает все индексы на единицу, завершающая не влияет на них).

person jhpratt    schedule 18.02.2019