ES6 теговые шаблоны практическое удобство использования
Я понимаю синтаксис шаблонов с тегами ES6. Чего я не вижу, так это практичности. Когда это лучше, чем передача параметра объекта, такого как настройки в AJAX в jQuery? $.ajax('url', { /*this guy here*/ })
Прямо сейчас я вижу только хитрый синтаксис, но не понимаю, зачем мне это нужно / использовать. Я также обнаружил, что команда TypeScript решила реализовать его (в 1.5) перед другими важными функциями. В чем заключается концепция шаблонов с тегами?
3 ответа
Вы можете использовать теговые шаблоны для создания API, которые более выразительны, чем обычные вызовы функций.
Например, я работаю над библиотекой проверки концепции для запросов SQL на массивах JS:
let admins = sql`SELECT name, id FROM ${users}
WHERE ${user => user.roles.indexOf('admin') >= 0}`
Обратите внимание, что это не имеет никакого отношения к интерполяции строк; он использует помеченные шаблоны для удобства чтения. Было бы сложно создать что-то, что будет читаться как интуитивно понятным с помощью простых вызовов функций - я думаю, у вас будет что-то вроде этого:
let admins = sql("SELECT name, id FROM $users WHERE $filter",
{ $users: users, $filter: (user) => user.roles.contains('admin') })
Этот пример - забавный побочный проект, но я думаю, что он показывает некоторые преимущества теговых шаблонов.
Другой пример, возможно, более очевидный, это i18n - тегированный шаблон может вставлять чувствительные к локали версии вашего ввода.
Смотрите объяснение Sitepoint:
Последний этап спецификации шаблонных строк заключается в добавлении пользовательской функции перед самой строкой для создания теговой шаблонной строки.
...
Например, вот фрагмент кода для блокировки строк, которые пытаются внедрить пользовательские элементы DOM:
var items = []; items.push("banana"); items.push("tomato"); items.push("light saber"); var total = "Trying to hijack your site <BR>"; var myTagFunction = function (strings,...values) { var output = ""; for (var index = 0; index < values.length; index++) { var valueString = values[index].toString(); if (valueString.indexOf(">") !== -1) { // Far more complex tests can be implemented here :) return "String analyzed and refused!"; } output += strings[index] + values[index]; } output += strings[index] return output; } result.innerHTML = myTagFunction `You have ${items.length} item(s) in your basket for a total of $${total}`;
Помеченные тегами строки шаблона могут использоваться для многих целей, таких как безопасность, локализация, создание собственного языка для конкретного домена и т. Д.
Они полезны, потому что функция может (почти) полностью определить значение текста внутри нее (почти = кроме заполнителей). Мне нравится использовать пример Стивена Левитана XRegExp
библиотека Неловко использовать регулярные выражения, определенные как строки, потому что вы должны дважды избегать вещей: один раз для строкового литерала и один раз для регулярного выражения. Это одна из причин, почему у нас есть литералы регулярных выражений в JavaScript.
Например, предположим, что я занимаюсь обслуживанием сайта и нахожу это:
var isSingleUnicodeWord = /^\w+$/;
... который предназначен для проверки, содержит ли строка только "буквы". Две проблемы: A) Существуют тысячи "словесных" символов в сфере человеческого языка, которые \w
не признает, потому что его определение ориентировано на английский язык; и Б) включает _
Многие (в том числе консорциум Unicode) утверждают, что это не "письмо".
Предположим, в моей работе я представил XRegExp
в кодовую базу. Поскольку я знаю, что это поддерживает \pL
(\p
для категорий Юникод и L
для "письма"), я мог бы быстро поменять это в:
var isSingleUnicodeWord = XRegExp("^\pL+$"); // WRONG
Тогда я удивляюсь, почему это не сработало, *facepalm*, и возвращаюсь назад и избегаю обратной косой черты, так как она используется строковым литералом:
var isSingleUnicodeWord = XRegExp("^\\pL+$");
// ---------------------------------^
Какая боль. Предположим, я мог бы написать реальное регулярное выражение, не беспокоясь о двойном экранировании?
Я могу: с помеченной функцией шаблона. Я могу поместить это в мою стандартную библиотеку:
function xrex(strings, ...values) {
const raw = strings.raw;
let result = "";
for (let i = 0; i < raw.length; ++i) {
result += raw[i];
if (i < values.length) { // `values` always has one fewer entry
result += values[i];
}
}
return XRegExp(result);
}
Или, альтернативно, это действительный вариант использования для reduce
и мы можем использовать деструктуризацию в списке аргументов:
function xrex({raw}, ...values) {
return XRegExp(
raw.reduce(
(acc, str, index) => acc + str + (index < values.length ? values[index] : ""),
""
)
);
}
И тогда я с радостью могу написать:
const isSingleUnicodeWord = xrex`^\pL+$`;
Пример:
// My tag function (defined once, then reused)
function xrex({raw}, ...values) {
const result = raw.reduce(
(acc, str, index) => acc + str + (index < values.length ? values[index] : ""),
""
);
console.log("Creating with:", result);
return XRegExp(result);
}
// Using it, with a couple of substitutions to prove to myself they work
let category = "L"; // L: Letter
let maybeEol = "$";
let isSingleUnicodeWord = xrex`^\p${category}+${maybeEol}`;
function test(str) {
console.log(str + ": " + isSingleUnicodeWord.test(str));
}
test("Русский"); // true
test("日本語"); // true
test("العربية"); // true
test("foo bar"); // false
test("$£"); // false
<script src="https://cdnjs.cloudflare.com/ajax/libs/xregexp/3.2.0/xregexp-all.min.js"></script>
Единственное, что я должен помнить сейчас, это то, что ${...}
особенный, потому что это заполнитель. В данном конкретном случае это не проблема, я вряд ли захочу применить квантификатор к утверждению конца ввода, но это совпадение...