Практическое удобство использования шаблонов с тегами ES6

Я понимаю синтаксис ES6 помеченных шаблонов . Чего я не вижу, так это практичности. Когда это лучше, чем передача параметра объекта, например настройки в AJAX jQuery? $.ajax('url', { /*this guy here*/ })

Прямо сейчас я вижу только сложный синтаксис, но я не понимаю, зачем мне это нужно/использовать. Я также обнаружил, что команда TypeScript решила реализовать его (в версии 1.5) перед другими важными функциями. В чем заключается концепция шаблонов строк с тегами?


person Gábor Imre    schedule 23.07.2015    source источник
comment
Что написано в вашей ссылке (но, возможно, я неправильно понимаю, что вы хотите): With them you are able to modify the output of template strings using a function.   -  person SPRBRN    schedule 23.07.2015
comment
Да, вы попали в точку. Но стоит ли это совершенно нового и довольно сложного языкового элемента? Я бы предпочел сделать для этого простую старую JS-функцию, это проще, не требует больших усилий. -- РЕДАКТИРОВАТЬ: я имею в виду, что я бы каким-то образом реализовал это с помощью функций POJS. (Одной функции может быть недостаточно.)   -  person Gábor Imre    schedule 23.07.2015
comment
Думаю, приятно то, что вы можете управлять семантикой. Ему вообще не нужно выполнять интерполяцию string. Я использовал шаблоны с тегами, чтобы упростить интерполяцию и создание узлов AST: rel="nofollow noreferrer">github.com/facebook/jscodeshift/blob/. Конечно, это можно было бы решить и по-другому, но, вероятно, не так лаконично и читабельно.   -  person Felix Kling    schedule 23.07.2015
comment
Я предполагаю, что эта функция в первую очередь предназначена для разработчиков фреймворков. (Angular2? React?) Я начинаю понимать в этом смысл, но это не типичная разработка промышленного проекта, а скорее какое-то мощное низкоуровневое изменение данных.   -  person Gábor Imre    schedule 23.07.2015


Ответы (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 — помеченный шаблон может вставлять чувствительные к локали версии вашего ввода.

person joews    schedule 23.07.2015

См. объяснение 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}`;

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

person SPRBRN    schedule 23.07.2015

Они полезны, потому что функция может (почти) полностью определить значение текста внутри нее (почти = кроме заполнителей). Мне нравится использовать в качестве примера XRegExpбиблиотеку Стивена Левитана. Неудобно использовать регулярные выражения, определенные как строки, потому что вам нужно дважды экранировать вещи: один раз для строкового литерала и один раз для регулярного выражения. Это одна из причин, по которой в JavaScript есть литералы регулярных выражений.

Например, предположим, что я занимаюсь обслуживанием сайта и обнаруживаю следующее:

var isSingleUnicodeWord = /^\w+$/;

... который предназначен для проверки того, содержит ли строка только «буквы». Две проблемы: A) В мире человеческого языка есть тысячи «словных» символов, которые \w не распознает, потому что его определение ориентировано на английский язык; и B) Он включает в себя _, что многие (включая консорциум Unicode) утверждают, что это не «буква».

Предположим, в своей работе я ввел XRegExp в кодовую базу. Поскольку я знаю, что он поддерживает \pL (\p для категорий Unicode и 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>

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

person T.J. Crowder    schedule 23.04.2017