tl; dr: Можно ли сделать литерал многоразового шаблона?
Я пытался использовать литералы шаблонов, но, кажется, просто не понимаю, и теперь я расстраиваюсь. Я имею в виду, я думаю, что понимаю это, но «это» не должно быть таким, как оно работает или как оно должно быть получено. Должно получиться иначе.
Все примеры, которые я вижу (даже шаблоны с тегами), требуют, чтобы «подстановки» выполнялись во время объявления, а не во время выполнения, что мне кажется совершенно бесполезным для шаблона. Может быть, я сумасшедший, но для меня «шаблон» - это документ, который содержит токены, которые заменяются, когда вы его используете, а не когда вы его создаете, иначе это просто документ (то есть строка). Шаблон хранится с токенами как токенами, и эти токены оцениваются, когда вы ... оцениваете его.
Все приводят ужасный пример, похожий на:
var a = 'asd';
return `Worthless ${a}!`
Это хорошо, но если я уже знаю a
, я бы просто return 'Worthless asd'
или return 'Worthless '+a
. В чем смысл? Шутки в сторону. Ладно, дело в лени; меньше плюсов, больше читабельности. Отлично. Но это не шаблон! Не ИМХО. И MHO - это все, что имеет значение! Проблема, IMHO, в том, что шаблон оценивается, когда он объявлен, поэтому, если вы это сделаете, IMHO:
var tpl = `My ${expletive} template`;
function go() { return tpl; }
go(); // SPACE-TIME ENDS!
Поскольку expletive
не объявлен, он выводит что-то вроде My undefined template
. Супер. На самом деле, по крайней мере, в Chrome я даже не могу объявить шаблон; он выдает ошибку, потому что expletive
не определен. Что мне нужно, так это иметь возможность выполнить замену после объявления шаблона:
var tpl = `My ${expletive} template`;
function go() { return tpl; }
var expletive = 'great';
go(); // My great template
Однако я не понимаю, как это возможно, поскольку на самом деле это не шаблоны. Даже когда вы говорите, что я должен использовать теги, нет, они не работают:
> explete = function(a,b) { console.log(a); console.log(b); }
< function (a,b) { console.log(a); console.log(b); }
> var tpl = explete`My ${expletive} template`
< VM2323:2 Uncaught ReferenceError: expletive is not defined...
Все это привело меня к мысли, что литералы шаблонов ужасно неверно названы и их следует называть тем, чем они являются на самом деле: heredocs . Я думаю, что "буквальная" часть должна была меня предупредить (например, неизменяемая)?
Я что-то упускаю? Есть ли (хороший) способ сделать многократно используемый шаблон литералом?
Я даю вам многоразовые шаблонные литералы :
> function out(t) { console.log(eval(t)); }
var template = `\`This is
my \${expletive} reusable
template!\``;
out(template);
var expletive = 'curious';
out(template);
var expletive = 'AMAZING';
out(template);
< This is
my undefined reusable
template!
This is
my curious reusable
template!
This is
my AMAZING reusable
template!
А вот и наивная «помощница» ...
function t(t) { return '`'+t.replace('{','${')+'`'; }
var template = t(`This is
my {expletive} reusable
template!`);
... чтобы было "лучше".
Я склонен называть их шаблонными гутералами из-за области, в которой они вызывают странные чувства.
источник
<strike>
тег.Ответы:
Чтобы эти литералы работали, как другие движки шаблонов, необходима промежуточная форма.
Лучший способ сделать это - использовать
Function
конструктор.Как и в случае с другими шаблонизаторами, вы можете получить эту строку из других мест, например из файла.
При использовании этого метода могут возникнуть проблемы, например, с использованием тегов шаблонов, которые трудно использовать, но их можно добавить, если вы сообразительны. У вас также не может быть встроенной логики JavaScript из-за поздней интерполяции. Это тоже можно исправить, если подумать.
источник
new Function(`return \`${template}\`;`)
Вы можете поместить строку шаблона в функцию:
То же самое можно сделать и с шаблоном с тегами:
Идея состоит в том, чтобы позволить синтаксическому анализатору шаблона отделять постоянные строки от переменной «slots», а затем возвращать функцию, которая исправляет все вместе, каждый раз на основе нового набора значений.
источник
reusable
можно реализовать так, чтобы он возвращал функцию, и вы использовали бы${0}
и${1}
внутри литерала вместо${a}
и${b}
. Затем вы можете использовать эти значения для ссылки на аргументы функции, аналогично тому, что делает Берги в своем последнем примере: stackoverflow.com/a/22619256/218196 (или, я думаю, это в основном то же самое).expression`a + ${node}`
создать узел BinaryExpression с существующим узлом ASTnode
. Внутри мы вставляем заполнитель для генерации действительного кода, анализируем его как AST и заменяем заполнитель переданным значением.Вероятно, самый чистый способ сделать это - использовать стрелочные функции (потому что на данный момент мы уже используем ES6)
... И для тегированных шаблонных литералов:
Это также позволяет избежать использования
eval()
или,Function()
которые могут вызвать проблемы с компиляторами и вызвать значительное замедление.источник
myTag
чтобы что-то делать. Например, используйте параметры ввода в качестве ключа для кеширования вывода.var reusable = (value: string) => `Value is ${value}`
.Ответ 2019 :
Примечание . Изначально библиотека ожидала, что пользователи будут очищать строки, чтобы избежать XSS. Версия 2 библиотеки больше не требует дезинфекции пользовательских строк (что веб-разработчики должны делать в любом случае), поскольку она
eval
полностью этого избегает .es6-dynamic-template
Модуль на НОМ это делает.В отличие от текущих ответов:
this
Строка шаблона не нужнаИспользование простое. Используйте одинарные кавычки, так как строка шаблона будет разрешена позже!
источник
10 * 20 = ${10 * 20}
чтобы это был аналогичный формат, но это даже не литералы шаблона es6 удаленноДа, вы можете сделать это, проанализировав вашу строку с шаблоном как JS с помощью
Function
(илиeval
) - но это не рекомендуется и разрешает атаку XSSПоказать фрагмент кода
Вместо этого вы можете безопасно вставлять
obj
поля объекта в шаблонstr
динамически следующим образомПоказать фрагмент кода
источник
.*?
средства нежадным - если убрать ,"?"
то фрагмент кода даст неправильный результатfunction taggedTemplate(template, data, matcher) { if (!template || !data) { return template; } matcher = matcher || /{(\w*)}/g; // {one or more alphanumeric characters with no spaces} return template.replace(matcher, function (match, key) { var value; try { value = data[key] } catch (e) { // } return value || ""; }); }
data = { a: 1, b: { c:2, d:3 } }
->b.c
?Упрощение ответа @metamorphasi;
источник
eval
.var hosting
) ЗДЕСЬ .Если вы не хотите использовать заказанные параметры или контекст / пространства имена для ссылки на переменных в шаблоне, например
${0}
,${this.something}
или${data.something}
, вы можете иметь шаблонную функцию , которая заботится о обзорного для вас.Пример того, как вы могли бы вызвать такой шаблон:
Функция шаблона:
Причуда в этом случае заключается в том, что вам просто нужно передать функцию (в примере я использовал стрелочную функцию), которая возвращает литерал шаблона ES6. Я думаю, что это незначительный компромисс, чтобы получить такую интерполяцию, которая нам нужна.
Вот он на GitHub: https://github.com/Adelphos/ES6-Reuseable-Template
источник
Object.values()
andObject.keys()
Короткий ответ - просто используйте _.template в lodash
источник
Возможно, мне что- то не хватает, потому что мое решение этой проблемы кажется мне настолько очевидным, что я очень удивлен, что никто не написал это уже в таком старом вопросе.
У меня для этого есть почти однострочный:
Вот и все. Когда я хочу повторно использовать шаблон и отложить разрешение замен, я просто делаю:
Применение этого тега возвращает обратно
'function'
(вместо'string'
), который игнорирует любые параметры, переданные в литерал. Затем его можно будет вызвать с новыми параметрами позже. Если параметр не имеет соответствующей замены, он становится'undefined'
.Расширенный ответ
Этот простой код является функциональным, но если вам нужно более детально проработанное поведение, можно применить ту же логику, и есть бесконечные возможности. Ты мог:
Вы можете сохранить исходные значения, переданные литералу в конструкции, и использовать их творчески при применении шаблона. Они могут стать флагами, валидаторами типов, функциями и т. Д. Это пример, в котором они используются как значения по умолчанию:
Затем:
Сделайте это, заключив эту логику в функцию, которая ожидает в качестве аргумента настраиваемую функцию, которая может быть применена при сокращении (при соединении частей литерала шаблона) и возвращает новый шаблон с настраиваемым поведением.
Затем вы могли бы, например, написать шаблоны, которые автоматически экранируют или дезинфицируют параметры при написании встроенных html, css, sql, bash ...
С помощью этого наивного (повторяю, наивного! ) Шаблона sql мы могли бы строить такие запросы:
Принять именованные параметры для замены: несложное упражнение, основанное на том, что уже было дано. В этом другом ответе есть реализация .
Сделать обратный объект ведет себя как
'string'
: Ну, это спорно, но может привести к интересным результатам. Показано в этом другом ответе .Разрешить параметры в глобальном пространстве имен на сайте вызова:
Ну, это то , что OP показал его добавление к нему, используя команду
, я имею в виду,evil
eval
. Это можно было бы сделать без негоeval
, просто выполнив поиск переданного имени переменной в глобальном (или оконном) объекте. Я не буду показывать, как это делать, потому что мне это не нравится. Замыкания - правильный выбор.источник
Это моя лучшая попытка:
Чтобы обобщить:
Если вы не используете E6, вы также можете:
Это кажется немного более кратким, чем предыдущие ответы.
https://repl.it/@abalter/reusable-JS-template-literal
источник
В целом я против использования зла
eval()
, но в данном случае это имеет смысл:Затем, если вы измените значения и снова вызовете eval (), вы получите новый результат:
Если вы хотите, чтобы это было в функции, то это можно записать так:
источник
eval
.eval()
явного вызова, в точности совпадает сeval()
, следовательно, в этом нет никакой пользы, так как это только затрудняет чтение кода.populate
функция не создает код динамически, ее не следует использоватьeval
со всеми ее недостатками.function populate(a,b) { return `${a}.${b}`; }
ОБНОВЛЕНО: следующий ответ ограничен одиночными именами переменных, поэтому такие шаблоны, как:,
'Result ${a+b}'
не подходят для этого случая. Однако вы всегда можете поиграть со значениями шаблона:ОРИГИНАЛЬНЫЙ ОТВЕТ:
Основываясь на предыдущих ответах, но создавая более «дружественную» служебную функцию:
Вы можете вызвать его так же:
И результирующая строка должна быть:
источник
`Result: ${a+b}`
Если вы ищете что-то довольно простое (только фиксированные переменные поля, без вычислений, условных операторов ...), но это также работает на стороне клиента в браузерах без поддержки строки шаблона, например IE 8,9,10,11 …
вот так:
источник
Меня раздражала дополнительная избыточность, необходимая для ввода текста
this.
каждый раз, поэтому я также добавил регулярное выражение для расширения таких переменных, как.a
tothis.a
.Решение:
Используйте как таковые:
источник
Я просто публикую один пакет npm, который просто выполняет эту работу. Глубоко вдохновлен этим ответом .
Его орудие убийственно простое. Желаю вам понравится.
источник
вы можете использовать встроенную стрелочную функцию, как это, определение:
использование:
источник
Строка шаблона среды выполнения
Тест
источник
источник