Чи можуть літерали шаблонів ES6 бути замінені під час виконання (або повторно використані)?


129

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...

Це все спонукало мене до думки, що буквальні шаблони жахливо називаються і їх слід називати такими, якими вони є насправді: гередоками . Я здогадуюсь, що "буквальна" частина повинна була мене перекинути (як у, незмінному)?

Я щось пропускаю? Чи є (хороший) спосіб зробити шаблон для багаторазового використання буквальним?


Надаю вам літературу шаблону для багаторазового використання :

> 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!`);

... щоб зробити його "кращим".

Я схильний називати їх шаблонами через область, з якої вони створюють закручені відчуття.


1
Він підтримує закреслене (але не в таких коментарях). Покладіть текст у <strike>тег.
Поні

Літеральні шаблони ES6 в основному для старомодної інтерполяції String. Якщо ви хочете, щоб динамічні шаблони використовували рулі тощо, або рішення шаблонного шаблону Pointy.
joews

1
Рядки шаблонів, незважаючи на назву, немає шаблонів . Дивіться також Виконання затримки для рядків шаблонів ES6
Бергі

8
Чи не могли б ви зробити свою публікацію трохи меншою мірою? Крім того, схоже, що ви мали намір написати підручник у форматі запитань, якщо ви це зробили, видаліть із запитання частину " Я даю вам ... " і опублікуйте її як відповідь .
Бергі

Я помічаю, що тут є багато хороших відповідей. Можливо, прийняти одного.
abalter

Відповіді:


86

Для того, щоб ці літерали працювали як інші двигуни шаблонів, необхідна форма посередника.

Найкращий спосіб зробити це - використовувати Functionконструктор.

const templateString = "Hello ${this.name}!";
const templateVars = {
    name: "world"    
}

const fillTemplate = function(templateString, templateVars){
    return new Function("return `"+templateString +"`;").call(templateVars);
}

console.log(fillTemplate(templateString, templateVars));

Як і в інших двигунах шаблонів, ви можете отримати цей рядок з інших місць, як файл.

За допомогою цього методу можуть виникнути проблеми, наприклад, теги шаблонів важкі у використанні, але їх можна додати, якщо ви розумні. Ви також не можете мати вбудовану логіку JavaScript через пізню інтерполяцію. Це також можна виправити за допомогою деякої думки.


8
Приємно! Можна навіть скористатисяnew Function(`return \`${template}\`;`)
Рубен Столк

І ці шаблони можуть бути складені або "включені" через аргументи, викликавши метод або передаючи в складений результат іншого шаблону.
Квентін Енглз

Квентін, що означає "без тегів шаблону"? Дякую!
mikemaccana

10
майте на увазі, що цей рядок шаблону "прихований" для трансляції (тобто веб-пакета), і таким чином НЕ буде перетворюватися на щось достатньо сумісне (тобто IE11) на стороні клієнта ...!
Френк Нокк

9
Уразливість XSS ? Деталі в ЦЕЙ JSFIDDLE
Kamil Kiełczewski

65

Ви можете розмістити рядок шаблону у функції:

function reusable(a, b) {
  return `a is ${a} and b is ${b}`;
}

Те ж саме можна зробити і з позначеним шаблоном:

function reusable(strings) {
  return function(... vals) {
    return strings.map(function(s, i) {
      return `${s}${vals[i] || ""}`;
    }).join("");
  };
}

var tagged = reusable`a is ${0} and b is ${1}`; // dummy "parameters"
console.log(tagged("hello", "world"));
// prints "a is hello b is world"
console.log(tagged("mars", "jupiter"));
// prints "a is mars b is jupiter"

Ідея полягає в тому, щоб аналізатор шаблонів розділив постійні рядки зі змінної "слотів", а потім повертав функцію, яка кожного разу виправляє їх разом на основі нового набору значень.


3
@FelixKling, що може бути; Я перевірю і виправлю це, якщо так. редагувати так, схоже, я залишив значну частину прикладу, що є функцією "багаторазового використання" :)
Pointy

@FelixKling Я не впевнений, що робити, тому що я взагалі не можу згадати, про що я думав у той час!
Pointy

1
Так, це не має сенсу бути або tbh;) Ви завжди можете його видалити .... але reusableможна реалізувати так, щоб він повертав функцію, а ви використовували б ${0}і ${1}всередині літералу замість ${a}і ${b}. Тоді ви можете використовувати ці значення для позначення аргументів функції, аналогічно тому, що робить Бергі в своєму останньому прикладі: stackoverflow.com/a/22619256/218196 (або, мабуть, це в основному те саме).
Фелікс Клінг

1
@FelixKling Гаразд, я думаю, що я придумав щось, що, принаймні, невиразно, в рамках ОП.
Pointy

3
Шаблони з тегами можуть бути дуже потужними, якщо результат насправді не є рядком. Наприклад, в одному з моїх проектів я використовую його для інтерполяції вузла AST. Наприклад, можна expression`a + ${node}`створити вузол BinaryExpression з існуючим вузлом AST node. Внутрішньо ми вставляємо заповнювач для заповнення дійсного коду, аналізуємо його як AST і замінюємо заповнювач заповнення на пройдене значення.
Фелікс Клінг

45

Напевно, найчистіший спосіб зробити це за допомогою стрілочних функцій (адже на даний момент ми вже використовуємо ES6)

var reusable = () => `This ${object} was created by ${creator}`;

var object = "template string", creator = "a function";
console.log (reusable()); // "This template string was created by a function"

object = "example", creator = "me";
console.log (reusable()); // "This example was created by me"

... І для тегів з літерами з тегами:

reusable = () => myTag`The ${noun} go ${verb} and `;

var noun = "wheels on the bus", verb = "round";
var myTag = function (strings, noun, verb) {
    return strings[0] + noun + strings[1] + verb + strings[2] + verb;
};
console.log (reusable()); // "The wheels on the bus go round and round"

noun = "racecars", verb = "fast";
myTag = function (strings, noun, verb) {
    return strings[0] + noun + strings[1] + verb;
};
console.log (reusable()); // "The racecars go fast"

Це також дозволяє уникнути використання eval()або, Function()що може спричинити проблеми з компіляторами і спричинити багато уповільнень.


Я думаю, що це один найкращий, тому що ви можете ввести деякі коди всередині функції, myTagщоб зробити якісь речі. Наприклад, використовуйте параметри введення як ключ для кешування виводу.
WOW

Я думаю, що це найкраща відповідь. Ви також можете додати параметри функції стрілки , які я думаю , що робить його ще чистіше: var reusable = (value: string) => `Value is ${value}`.
haggisandchips

13

Відповідь 2019 року :

Примітка : Бібліотека спочатку очікувала, що користувачі очистять рядки, щоб уникнути XSS. Версія 2 бібліотеки більше не вимагає дезінфекції рядків користувача (що все-таки слід робити веб-розробникам), оскільки це дозволяє уникнутиeval повністю .

es6-dynamic-templateМодуль на НОМ це робить.

const fillTemplate = require('es6-dynamic-template');

На відміну від нинішніх відповідей:

  • Він використовує рядки шаблонів ES6, не подібного формату. Оновлення версія 2 використовує аналогічний формат, а не рядки шаблону ES6, щоб запобігти використанню несанітизованих рядків введення.
  • Це не потрібно this в рядку шаблону
  • Ви можете вказати рядок шаблону та змінні в одній функції
  • Це підтримуваний, оновлений модуль, а не copypasta від StackOverflow

Використання просте. Використовуйте одинарні лапки, оскільки рядок шаблону буде вирішено пізніше!

const greeting = fillTemplate('Hi ${firstName}', {firstName: 'Joe'});

Якщо ви використовуєте це з React Native, це спеціально зламається на Android. Виконання вузла Android не підтримує динамічні шаблони, лише попередньо заповнені
Олівер Діксон

1
Це рішення, яке я використовую в своїх особистих проектах, і воно працює бездоганно. Насправді я думаю, що погана ідея використовувати занадто багато бібліотек, особливо для невеликих утиліт, як це.
Олівер Діксон

1
Уразливість XSS ? Деталі в ЦЬОМУ ФІДЛІ
Каміль Кичевчевський

1
@kamil Лише XSS, якщо ви а) даєте користувачам можливість створювати b) не саніруйте вхідні рядки. Я додам попередження, що люди повинні санітувати введення користувачів.
mikemaccana

1
Це дистанційно не використовує літерали шаблону es6. Спробуйте, 10 * 20 = ${10 * 20}можливо, це схожий формат, але це навіть не віддалено літеральні шаблони
es6

12

Так, ви можете зробити це, розібравши рядок із шаблоном як JS Function(або eval) - але це не рекомендується і дозволити атаку XSS

Натомість ви можете сміливо вставляти об’єкти objв шаблон шаблону strдинамічним способом наступним чином

let inject = (str, obj) => str.replace(/\${(.*?)}/g, (x,g)=> obj[g]);


Це метод, який я використовую, і він добре працює. Хороший приклад! Чи? після * в довідці RegEx, хоча? Я не експерт по RegEx, але я здогадуюсь, оскільки * означає нуль або більше (і ви хочете, щоб "більше" в цьому випадку) немає жадного обмеження?
Gen1-1

@ Gen1-1 - це .*?засоби, які не є жадібними - якщо ви видалите, "?"то фрагмент дасть неправильний результат
Kamil Kiełczewski

Ти прав, моя помилка. Я не використовую $ у своїх шаблонах і використовую RegEx: / {(\ w *)} / g, оскільки у тегу у мене ніколи немає пробілів, але. *? також працює. Я використовую: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 || ""; }); }
Gen1-1

@ Gen1-1 чи можливі також вкладені дані? як data = { a: 1, b: { c:2, d:3 } }-> b.c?
мюша

1
@muescha Ви б змінили рядок: value = data [key], щоб використовувати рекурсію та шукати весь об’єкт даних та вкладені об’єкти, поки ви не знайшли властивість. Приклади: codereview.stackexchange.com/questions/73714/… та mikedoesweb.com/2016/es6-depth-first-object-tree-search
Gen1-1

9

Спрощення відповіді, наданої @metamorphasi;

const fillTemplate = function(templateString, templateVars){
  var func = new Function(...Object.keys(templateVars),  "return `"+templateString +"`;")
  return func(...Object.values(templateVars));
}

// Sample
var hosting = "overview/id/d:${Id}";
var domain = {Id:1234, User:22};
var result = fillTemplate(hosting, domain);

console.log(result);


Цей код є більш зрозумілим, ніж провідна відповідь. Отримав моє голосування :)
ymz

Це повинно дозволяти вам використовувати змінні або зовнішні файли (у NodeJS) як шаблони або динамічно будувати їх під час виконання. Без використання eval.
b01

Уразливість XSS ? Скрипка зі шкідливим кодом (змінною var hosting) ТУТ .
Kamil Kiełczewski

7

Якщо ви не хочете використовувати упорядковані параметри або контекст / простори імен для посилання на змінні у вашому шаблоні, наприклад ${0} , ${this.something}або${data.something} , ви можете мати шаблонну функцію , яка піклується про оглядового для вас.

Приклад того, як можна було назвати такий шаблон:

const tempGreet = Template(() => `
  <span>Hello, ${name}!</span>
`);
tempGreet({name: 'Brian'}); // returns "<span>Hello, Brian!</span>"

Функція Шаблон:

function Template(cb) {
  return function(data) {
    const dataKeys = [];
    const dataVals = [];
    for (let key in data) {
      dataKeys.push(key);
      dataVals.push(data[key]);
    }
    let func = new Function(...dataKeys, 'return (' + cb + ')();');
    return func(...dataVals);
  }
}

Примха в цьому випадку полягає в тому, що вам просто потрібно передати функцію (у прикладі я використовував функцію зі стрілкою), яка повертає шаблон шаблону ES6 буквально. Я думаю, що це незначна компромісна ситуація, щоб отримати таку повторну інтерполяцію, яку ми повторюємо.

Ось це на GitHub: https://github.com/Adelphos/ES6-Reuseable-Template


3
Це добре, але мінімізація (vals, func тощо) є непотрібною, "cb" - це не зворотний виклик (це повністю код синхронізації), і ви можете просто скористатися Object.values()іObject.keys()
mikemaccana

3

Коротка відповідь - просто використовувати _.template в квартирі

// Use the ES template literal delimiter as an "interpolate" delimiter.
// Disable support by replacing the "interpolate" delimiter.
var compiled = _.template('hello ${ user }!');
compiled({ 'user': 'pebbles' });
// => 'hello pebbles!'

3

Я щось пропускаю? Чи існує [гарний] спосіб зробити шаблон для багаторазового використання буквальним?

Можливо, я чогось не вистачає, тому що моє вирішення цього питання мені здається настільки очевидним, що я дуже здивований, що ніхто не писав цього вже в такому старому питанні.

У мене є майже один вкладиш для цього:

function defer([first, ...rest]) {
  return (...values) => rest.reduce((acc, str, i) => acc + values[i] + str, first);
}

Це все. Коли я хочу повторно використовувати шаблон і відкласти роздільну здатність підстановок, я просто виконую:

> t = defer`My template is: ${null} and ${null}`;
> t('simple', 'reusable');          // 'My template is: simple and reusable'
> t('obvious', 'late to the party'; // 'My template is: obvious and late to the party'
> t(null);                          // 'My template is: null and undefined'
>
> defer`Choose: ${'ignore'} / ${undefined}`(true, false); // 'Choose: true / false'

Застосування цього тегу повертає назад 'function'(замість а 'string'), який ігнорує будь-які параметри, передані буквальному. Тоді його можна буде викликати за допомогою нових параметрів пізніше. Якщо параметр не має відповідної заміни, він стає 'undefined'.


Розширена відповідь

Цей простий код є функціональним, але якщо вам потрібна більш досконала поведінка, можна застосувати ту саму логіку і існують нескінченні можливості. Ти міг:

  1. Скористайтеся оригінальними параметрами:

Ви можете зберігати оригінальні значення, передані літералу в побудові, і використовувати їх творчим шляхом при застосуванні шаблону. Вони можуть стати прапорами, типовими валідаторами, функціями тощо. Це приклад, який використовує їх як значення за замовчуванням:

    function deferWithDefaults([first, ...rest], ...defaults) {
      return (...values) => rest.reduce((acc, curr, i) => {
        return acc + (i < values.length ? values[i] : defaults[i]) + curr;
      }, first);
    }

Тоді:

    > t = deferWithDefaults`My template is: ${'extendable'} and ${'versatile'}`;
    > t('awesome');                 // 'My template is: awesome and versatile' 
  1. Написати фабрику шаблонів:

Зробіть це, обернувши цю логіку у функції, яка очікує, як аргумент, власну функцію, яка може бути застосована у скороченні (при приєднанні до фрагментів шаблону буквально) та повертає новий шаблон із користувацькою поведінкою.

    const createTemplate = fn => function (strings, ...defaults) {
      const [first, ...rest] = strings;
      return (...values) => rest.reduce((acc, curr, i) => {
        return acc + fn(values[i], defaults[i]) + curr;
      }, first);
    };

Тоді ви можете, наприклад, писати шаблони, які автоматично виходять або санірують параметри при написанні вбудованих html, css, sql, bash ...

    function sqlSanitize(token, tag) {
      // this is a gross simplification, don't use in production.
      const quoteName = name => (!/^[a-z_][a-z0-9_$]*$/.test(name) ? `"${name.replace(/"/g, '""')}"` : name);
      const quoteValue = value => (typeof value == 'string' ? `'${value.replace(/'/g, "''")}'` : value);
      switch (tag) {
        case 'table':
          return quoteName(token);
        case 'columns':
          return token.map(quoteName);
        case 'row':
          return token.map(quoteValue);
        default:
          return token;
      }
    }

    const sql = createTemplate(sqlSanitize);

За допомогою цього наївного (повторююсь, наївного! ) Sql шаблону ми могли б будувати такі запити:

    > q  = sql`INSERT INTO ${'table'} (${'columns'})
    ... VALUES (${'row'});`
    > q('user', ['id', 'user name', 'is"Staff"?'], [1, "O'neil", true])
    // `INSERT INTO user (id,"user name","is""Staff""?")
    // VALUES (1,'O''neil',true);`
  1. Прийміть названі параметри для заміни: Не дуже важка вправа, заснована на тому, що вже було дано. У цій іншій відповіді є реалізація .

  2. Змусити об'єкт, що повертається, вести себе як 'string': Ну, це суперечливо, але може призвести до цікавих результатів. Показано в цій іншій відповіді .

  3. Розв’яжіть параметри всесвітнього простору імен на сайті виклику:

Надаю вам літературу шаблону для багаторазового використання:

Ну, це те , що OP показав його додавання до нього, використовуючи команду evil, я маю в виду, eval. Це можна зробити без evalпросто пошуку за допомогою переданого імені змінної в глобальний (або віконний) об'єкт. Я не покажу, як це зробити, бо мені це не подобається. Закриття - правильний вибір.


2

Це моя найкраща спроба:

var s = (item, price) => {return `item: ${item}, price: $${price}`}
s('pants', 10) // 'item: pants, price: $10'
s('shirts', 15) // 'item: shirts, price: $15'

Для узагальнення:

var s = (<variable names you want>) => {return `<template with those variables>`}

Якщо ви не працюєте з E6, ви також можете зробити:

var s = function(<variable names you want>){return `<template with those variables>`}

Це здається трохи більш стислим, ніж попередні відповіді.

https://repl.it/@abalter/reusable-JS-template-literal


2

Взагалі я проти використання зла eval(), але в цьому випадку має сенс:

var template = "`${a}.${b}`";
var a = 1, b = 2;
var populated = eval(template);

console.log(populated);         // shows 1.2

Тоді якщо ви знову зміните значення та зателефонуєте eval (), ви отримаєте новий результат:

a = 3; b = 4;
populated = eval(template);

console.log(populated);         // shows 3.4

Якщо ви хочете, щоб він був у функції, то його можна записати так:

function populate(a, b){
  return `${a}.${b}`;
}

Якщо ви пишете функцію, що включає шаблон, вам точно не слід користуватися eval.
Бергі

@Bergi Чому? Чим вона відрізняється від вашої реалізації?
isapir

2
Причини, які я, здається, знаю, стосуються будь-якого динамічно складеного коду. Записати функцію так, щоб вона будувала результат без eval()виразного виклику , точно така ж, як eval(), отже, в цьому немає ніякої користі, оскільки це лише ускладнює читання коду.
isapir

1
Саме так. А оскільки ваша populateфункція не динамічно будує код, вона не повинна використовуватись evalз усіма її недоліками.
Бергі

6
ваша функція може бути просто function populate(a,b) { return `${a}.${b}`; }eval нічого не додає
Vitim.us

1

ОНОВЛЕНО: Наступна відповідь обмежена іменами однієї змінної, тому шаблони типу: 'Result ${a+b}'не є дійсними для цього випадку. Однак ви завжди можете грати зі значеннями шаблону:

format("This is a test: ${a_b}", {a_b: a+b});

ОРИГІНАЛЬНИЙ ВІДПОВІДЬ:

Спираючись на попередні відповіді, але створюючи більш "дружню" функцію утиліти:

var format = (template, params) => {
    let tpl = template.replace(/\${(?!this\.)/g, "${this.");
    let tpl_func = new Function(`return \`${tpl}\``);

    return tpl_func.call(params);
}

Ви можете викликати його так само:

format("This is a test: ${hola}, second param: ${hello}", {hola: 'Hola', hello: 'Hi'});

І отриманий рядок повинен бути:

'This is a test: Hola, second param: Hi'

Що з таким шаблоном? `Result: ${a+b}`
Атіріс

1
Привіт @Atiris, ти маєш рацію. Це обмеження, я оновив свою відповідь.
Роберто

1

Якщо ви шукаєте щось досить просте (просто фіксовані змінні поля, відсутність обчислень, умовні умови ...), але це працює також на стороні клієнта у браузерах без підтримки рядкових шаблонів, як IE 8,9,10,11 ...

ось і ми:

fillTemplate = function (templateString, templateVars) {
    var parsed = templateString;
    Object.keys(templateVars).forEach(
        (key) => {
            const value = templateVars[key]
            parsed = parsed.replace('${'+key+'}',value)
        }
    )
    return parsed
}

Це зробить пошук для кожної змінної. Є ще один спосіб, який замінює всі випадки виникнення відразу, що я реалізував у цьому модулі: safe-es6-template
Aalex Gabi

1

Я був роздратований додаткової надмірності , необхідної , щоб друкувати this.кожен раз, так що я також додав регулярний вираз для розширення змінних , як .aвthis.a .

Рішення:

const interp = template => _thisObj =>
function() {
    return template.replace(/\${([^}]*)}/g, (_, k) =>
        eval(
            k.replace(/([.a-zA-Z0-9$_]*)([a-zA-Z0-9$_]+)/, (r, ...args) =>
                args[0].charAt(0) == '.' ? 'this' + args[0] + args[1] : r
            )
        )
    );
}.call(_thisObj);

Використовувати як таке:

console.log(interp('Hello ${.a}${.b}')({ a: 'World', b: '!' }));
// outputs: Hello World!

1

Я просто публікую один пакет npm, який може просто виконати цю роботу. Глибоко натхненний цією відповіддю .

const Template = require('dynamic-template-string');

var tpl = new Template('hello ${name}');

tpl.fill({name: 'world'}); // ==> 'hello world';
tpl.fill({name: 'china'}); // ==> 'hello china';

Її реалізація смертельно проста. Бажаю, тобі сподобається.


module.exports = class Template {
  constructor(str) {
    this._func = new Function(`with(this) { return \`${str}\`; }`);
  }

  fill(data) {
    return this._func.call(data);
  }
}

1

ви можете використовувати функцію стрілки вбудованої форми, як це, визначення:

const template = (substitute: string) => `[^.?!]*(?<=[.?\s!])${substitute}(?=[\s.?!])[^.?!]*[.?!]`;

використання:

console.log(template('my replaced string'));

1

Рядок шаблону виконання

var templateString = (template, values) => {
    let output = template;
    Object.keys(values)
        .forEach(key => {
        output = output.replace(new RegExp('\\$' + `{${key}}`, 'g'), values[key]);
    });
    return output;
};

Тест

console.debug(templateString('hello ${word} world', {word: 'wonderful'}));

0

const fillTemplate = (template, values) => {
  template = template.replace(/(?<=\${)\w+(?=})/g, v=>"this."+v);
  return Function.apply(this, ["", "return `"+template+"`;"]).call(values);
};

console.log(fillTemplate("The man ${man} is brother of ${brother}", {man: "John", brother:"Peter"}));
//The man John is brother of Peter

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.