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>

Единственное, что я должен помнить сейчас, это то, что ${...} особенный, потому что это заполнитель. В данном конкретном случае это не проблема, я вряд ли захочу применить квантификатор к утверждению конца ввода, но это совпадение...

Другие вопросы по тегам