¿Se pueden sustituir los literales de plantilla de ES6 en tiempo de ejecución (o reutilizar)?


129

tl; dr: ¿Es posible hacer un literal de plantilla reutilizable?

He intentado usar plantillas literales, pero supongo que no lo entiendo y ahora me estoy frustrando. Quiero decir, creo que lo entiendo, pero "eso" no debería ser cómo funciona, o cómo debería ser. Debería ser diferente.

Todos los ejemplos que veo (incluso las plantillas etiquetadas) requieren que las "sustituciones" se realicen en tiempo de declaración y no en tiempo de ejecución, lo que me parece completamente inútil para una plantilla. Tal vez esté loco, pero una "plantilla" para mí es un documento que contiene tokens que se sustituyen cuando lo usas, no cuando lo creas, de lo contrario es solo un documento (es decir, una cadena). Una plantilla se almacena con los tokens como tokens y esos tokens se evalúan cuando ... la evalúas.

Todo el mundo cita un ejemplo horrible similar a:

var a = 'asd';
return `Worthless ${a}!`

Eso está bien, pero si ya lo sé a, lo haría simplemente return 'Worthless asd'o return 'Worthless '+a. ¿Cuál es el punto de? Seriamente. Está bien, el punto es la pereza; menos ventajas, más legibilidad. Excelente. ¡Pero eso no es una plantilla! No en mi humilde opinión. ¡Y MHO es todo lo que importa! El problema, en mi humilde opinión, es que la plantilla se evalúa cuando se declara, así que, si lo hace, en mi humilde opinión:

var tpl = `My ${expletive} template`;
function go() { return tpl; }
go(); // SPACE-TIME ENDS!

Como expletiveno se declara, genera algo como My undefined template. Súper. En realidad, al menos en Chrome, ni siquiera puedo declarar la plantilla; arroja un error porque expletiveno está definido. Lo que necesito es poder hacer la sustitución después de declarar la plantilla:

var tpl = `My ${expletive} template`;
function go() { return tpl; }
var expletive = 'great';
go(); // My great template

Sin embargo, no veo cómo esto es posible, ya que estas no son realmente plantillas. Incluso cuando dices que debería usar etiquetas, no, no funcionan:

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

Todo esto me ha llevado a creer que los literales de plantilla están horriblemente mal nombrados y deberían llamarse como realmente son: heredocs . ¿Supongo que la parte "literal" debería haberme alertado (como en, inmutable)?

¿Me estoy perdiendo de algo? ¿Existe una (buena) manera de hacer literal una plantilla reutilizable?


Te doy, plantillas literales reutilizables :

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

Y aquí hay una función de "ayuda" ingenua ...

function t(t) { return '`'+t.replace('{','${')+'`'; }
var template = t(`This is
my {expletive} reusable
template!`);

...para hacerlo mejor".

Me inclino a llamarlos guías de plantilla por el área desde la que producen sensaciones retorcidas.


1
Admite tachado (pero no en comentarios como este). Pon tu texto en una <strike>etiqueta.
Puntiagudo

Los literales de plantilla de ES6 son principalmente para la interpolación de cadenas pasada de moda. Si desea plantillas dinámicas, use Handlebars, etc., o la solución de plantilla etiquetada de Pointy.
joews

1
Las cadenas de plantillas, a pesar del nombre, no son plantillas . Consulte también Aplazar la ejecución de las cadenas de plantillas de ES6
Bergi

8
¿Podrías hacer tu publicación un poco menos obscena? Además, parece que tenía la intención de escribir un tutorial en formato de preguntas y respuestas . Si lo hizo, elimine la parte " Te doy ... " de su pregunta y publíquela como respuesta .
Bergi

Noto que aquí hay muchas buenas respuestas. Quizás acepte uno.
abalter

Respuestas:


86

Para que estos literales funcionen como otros motores de plantilla, debe haber un formulario intermedio.

La mejor manera de hacer esto es usar el Functionconstructor.

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

Al igual que con otros motores de plantillas, puede obtener esa cadena de otros lugares, como un archivo.

Puede haber problemas al usar este método, como que las etiquetas de plantilla son difíciles de usar, pero se pueden agregar si eres inteligente. Tampoco puede tener lógica JavaScript en línea debido a la interpolación tardía. Esto también se puede remediar con un poco de pensamiento.


8
¡Agradable! Incluso puedes usarnew Function(`return \`${template}\`;`)
Ruben Stolk

Y estas plantillas se pueden componer o "incluir" mediante argumentos llamando a un método o pasando el resultado compilado de otra plantilla.
Quentin Engles

Quentin, ¿qué significa "sin etiquetas de plantilla"? ¡Gracias!
mikemaccana

10
tenga en cuenta que esta cadena de plantilla está un poco 'oculta' para la transpilación (es decir, paquete web) y, por lo tanto, NO se transpilará a algo suficientemente compatible (es decir, IE11) en el lado del cliente ...!
Frank Nocke

9
Vulnerabilidad XSS ? Detalles en ESTE JSFIDDLE
Kamil Kiełczewski

65

Puede poner una cadena de plantilla en una función:

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

Puedes hacer lo mismo con una plantilla etiquetada:

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"

La idea es dejar que el analizador de plantillas separe las cadenas constantes de las "ranuras" de la variable y luego devuelva una función que vuelva a unirlo todo en función de un nuevo conjunto de valores cada vez.


3
@FelixKling que puede ser; Lo comprobaré y lo arreglaré si es así. editar sí, parece que omití una parte importante del ejemplo, que es la función "reutilizable" :)
Puntiagudo

@FelixKling ¡No estoy seguro de qué hacer porque no puedo recordar en absoluto lo que estaba pensando en ese momento!
Puntiagudo

1
Sí, no tiene mucho sentido ser tbh;) Siempre puedes eliminarlo ... pero reusablepodría implementarse para que devuelva una función, y usarías ${0}y ${1}dentro del literal en lugar de ${a}y ${b}. Luego puede usar esos valores para referirse a los argumentos de la función, similar a lo que hace Bergi en su último ejemplo: stackoverflow.com/a/22619256/218196 (o supongo que es básicamente lo mismo).
Felix Kling

1
@FelixKling OK, creo que se me ocurrió algo que es al menos vagamente en la línea del OP.
Puntiagudo

3
Las plantillas etiquetadas pueden ser realmente poderosas si el resultado en realidad no es una cadena. Por ejemplo, en uno de mis proyectos, lo uso para hacer interpolación de nodos AST. Por ejemplo, se puede hacer expression`a + ${node}`para construir un nodo BinaryExpression con un nodo AST existente node. Internamente insertamos un marcador de posición para generar un código válido, lo analizamos como un AST y reemplazamos el marcador de posición con el valor pasado.
Felix Kling

45

Probablemente la forma más limpia de hacer esto es con las funciones de flecha (porque en este punto, ya estamos usando 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"

... Y para literales de plantilla etiquetados:

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"

Esto también evita el uso de eval()o Function()que puede causar problemas con los compiladores y causar mucha ralentización.


Creo que este es uno de los mejores porque puedes inyectar algunos códigos dentro de la función myTagpara hacer algunas cosas. Por ejemplo, utilice los parámetros de entrada como clave para almacenar en caché la salida.
WOW

Creo que esta es la mejor respuesta. También puede añadir parámetros a la función de flecha que creo que hace que sea aún más limpio: var reusable = (value: string) => `Value is ${value}`.
haggisandchips

13

2019 respuesta :

Nota : La biblioteca originalmente esperaba que los usuarios desinfectaran las cadenas para evitar XSS. La versión 2 de la biblioteca ya no requiere que se desinfecten las cadenas de usuario (lo que los desarrolladores web deberían hacer de todos modos), ya que evitaeval completo.

El es6-dynamic-templatemódulo de npm hace esto.

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

A diferencia de las respuestas actuales:

  • Utiliza cadenas de plantilla ES6, no un formato similar. Actualizar versión de 2 usa un formato similar, en lugar de cadenas de plantilla ES6, para evitar que los usuarios utilicen cadenas de entrada no higienizadas.
  • No necesita this en la cadena de la plantilla
  • Puede especificar la cadena de plantilla y las variables en una sola función
  • Es un módulo actualizado y mantenido, en lugar de copypasta de StackOverflow

El uso es simple. Utilice comillas simples ya que la cadena de la plantilla se resolverá más adelante.

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

Si está usando esto con React Native, se romperá especialmente en Android. El tiempo de ejecución del nodo de Android no admite plantillas dinámicas, solo las precargadas
Oliver Dixon

1
Esta es una solución que utilizo en mis proyectos personales y funciona a la perfección. De hecho, creo que es una mala idea usar demasiadas bibliotecas, especialmente para pequeñas utilidades como esta.
Oliver Dixon

1
Vulnerabilidad XSS ? Detalles en este violín
Kamil Kiełczewski

1
@kamil Solo XSS si a) les da a los usuarios la capacidad de crear b) no desinfecta las cadenas de entrada. Sin embargo, agregaré una advertencia de que la gente debería desinfectar la entrada del usuario.
mikemaccana

1
Esto no usa de forma remota literales de plantilla es6. Intente 10 * 20 = ${10 * 20}para que sea un formato similar, pero no es ni remotamente literal de plantilla
es6

12

Sí, puede hacerlo analizando su cadena con la plantilla como JS por Function(o eval), pero esto no se recomienda y permite el ataque XSS

En su lugar, puede insertar de forma seguraobj campos de objeto en la plantilla strde forma dinámica de la siguiente manera

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


Este es el método que utilizo y ha funcionado bien. ¡Buen ejemplo! ¿El? ¿Después del * en la ayuda de RegEx? No soy un experto en RegEx, pero supongo que, dado que * significa cero o más (y en este caso, desea el "más"), ¿no es necesario aplicar la restricción codiciosa?
Gen1-1

@ Gen1-1 el .*? medios no codiciosos : si elimina "?", el fragmento dará un resultado incorrecto
Kamil Kiełczewski

Tienes razón, mi error. No uso $ en mis plantillas y uso RegEx: / {(\ w *)} / g porque nunca tengo espacios en la etiqueta, pero. *? también funciona. Yo uso: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 ¿también hay datos anidados posibles? como data = { a: 1, b: { c:2, d:3 } }-> b.c?
muescha

1
@muescha Cambiaría la línea: valor = datos [clave], para usar la recursividad y buscar todo su objeto de datos y objetos anidados hasta que encuentre la propiedad. Ejemplos: codereview.stackexchange.com/questions/73714/… y mikedoesweb.com/2016/es6-depth-first-object-tree-search
Gen1-1

9

Simplificando la respuesta proporcionada por @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);


Este código es más autoexplicativo que la respuesta principal. Tengo mi voto a favor :)
ymz

Esto debería permitirle usar variables o archivos externos (en NodeJS) como plantillas o construirlos dinámicamente en tiempo de ejecución. Sin el uso de eval.
b01

Vulnerabilidad XSS ? Juega con código malicioso (variable var hosting) AQUÍ .
Kamil Kiełczewski

7

Si no desea utilizar los parámetros ordenados o contexto / espacios de nombres para hacer referencia a las variables en su plantilla, por ejemplo ${0}, ${this.something}o ${data.something}, puede tener una función de plantilla que se encarga de la definición del alcance para usted.

Ejemplo de cómo podría llamar a una plantilla de este tipo:

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

La función de plantilla:

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);
  }
}

La peculiaridad en este caso es que solo tiene que pasar una función (en el ejemplo, usé una función de flecha) que devuelve el literal de la plantilla ES6. Creo que es una compensación menor obtener el tipo de interpolación reutilizable que buscamos.

Aquí está en GitHub: https://github.com/Adelphos/ES6-Reuseable-Template


3
Esto es bueno, pero la minificación (vals, func, etc.) es innecesaria, 'cb' no es una devolución de llamada (esto es un código completamente sincronizado), y puedes usar Object.values()yObject.keys()
mikemaccana

3

La respuesta corta es simplemente usar _.template en lodash

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

¿Me estoy perdiendo de algo? ¿Existe una [buena] forma de hacer literal una plantilla reutilizable?

Tal vez me esté perdiendo algo, porque mi solución a este problema me parece tan obvia que estoy muy sorprendido de que nadie haya escrito eso ya en una pregunta tan antigua.

Tengo casi una línea para eso:

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

Eso es todo. Cuando quiero reutilizar una plantilla y diferir la resolución de las sustituciones, simplemente hago:

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

La aplicación de esta etiqueta devuelve un 'function'(en lugar de a 'string') que ignora cualquier parámetro pasado al literal. Entonces se puede llamar con nuevos parámetros más tarde. Si un parámetro no tiene un reemplazo correspondiente, se convierte en 'undefined'.


Respuesta extendida

Este código simple es funcional, pero si necesita un comportamiento más elaborado, se puede aplicar esa misma lógica y hay infinitas posibilidades. Tú podrías:

  1. Utilice los parámetros originales:

Puede almacenar los valores originales pasados ​​al literal en la construcción y usarlos de manera creativa al aplicar la plantilla. Podrían convertirse en banderas, validadores de tipos, funciones, etc. Este es un ejemplo que los usa como valores predeterminados:

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

Luego:

    > t = deferWithDefaults`My template is: ${'extendable'} and ${'versatile'}`;
    > t('awesome');                 // 'My template is: awesome and versatile' 
  1. Escribe una fábrica de plantillas:

Hazlo envolviendo esta lógica en una función que espera, como argumento, una función personalizada que se pueda aplicar en la reducción (al unir las piezas del literal de la plantilla) y devuelve una nueva plantilla con comportamiento personalizado.

    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);
    };

Luego, podría, por ejemplo, escribir plantillas que escapen automáticamente o desinfecten parámetros al escribir html, css, sql, bash incrustados ...

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

Con esta plantilla sql ingenua (repito, ingenua! ) Podríamos construir consultas como esta:

    > 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. Aceptar parámetros nombrados para la sustitución: un ejercicio no tan difícil, basado en lo que ya se dio. Hay una implementación en esta otra respuesta .

  2. Hacer que el objeto de retorno se comporte como 'string': Bueno, esto es controvertido, pero podría conducir a resultados interesantes. Se muestra en esta otra respuesta .

  3. Resuelva los parámetros dentro del espacio de nombres global en el sitio de la llamada:

Te doy, plantillas literales reutilizables:

Bueno, esto es lo que mostró OP es su adenda, utilizando el comando evil, es decir, eval. Esto podría hacerse sin eval, simplemente buscando el nombre de la variable pasada en el objeto global (o ventana). No mostraré cómo hacerlo porque no me gusta. Los cierres son la elección correcta.


2

Este es mi mejor intento:

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

Para generalizar:

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

Si no está ejecutando E6, también puede hacer:

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

Esto parece ser un poco más conciso que las respuestas anteriores.

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


2

En general, estoy en contra de usar el mal eval(), pero en este caso tiene sentido:

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

console.log(populated);         // shows 1.2

Luego, si cambia los valores y llama a eval () nuevamente, obtiene el nuevo resultado:

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

console.log(populated);         // shows 3.4

Si lo desea en una función, entonces se puede escribir así:

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

Si está escribiendo una función que incluye la plantilla, definitivamente no debe usarla eval.
Bergi

@Bergi ¿Por qué? ¿En qué se diferencia de su implementación?
isapir

2
Las razones por las que "parece que conozco" se aplican a cualquier código construido dinámicamente. Escribir la función para que construya el resultado sin llamareval() explícitamente es exactamente lo mismo que eval(), por lo tanto, no hay ningún beneficio en ello, ya que solo hace que el código sea más difícil de leer.
isapir

1
Exactamente. Y dado que su populatefunción no construye dinámicamente el código, no debería usarse evalcon todos sus inconvenientes.
Bergi

6
su función podría ser simplemente que function populate(a,b) { return `${a}.${b}`; }eval no agrega nada
Vitim.us

1

ACTUALIZADO: La siguiente respuesta está limitada a nombres de variables individuales, por lo que las plantillas como: 'Result ${a+b}'no son válidas para este caso. Sin embargo, siempre puedes jugar con los valores de la plantilla:

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

RESPUESTA ORIGINAL:

Basado en las respuestas anteriores pero creando una función de utilidad más "amigable":

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

    return tpl_func.call(params);
}

Puede invocarlo como:

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

Y la cadena resultante debería ser:

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

¿Qué tal una plantilla como esta? `Result: ${a+b}`
Atiris

1
Hola @Atiris, tienes razón, esa es una limitación, he actualizado mi respuesta.
Roberto

1

Si está buscando algo bastante simple (solo campos variables fijos, sin cálculos, condicionales ...) pero eso también funciona en el lado del cliente en navegadores sin soporte de cadenas de plantillas como IE 8,9,10,11 ...

aquí vamos:

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

Esto hará una búsqueda para cada variable. Hay otra forma que reemplaza todas las ocurrencias a la vez que implementé en este módulo: safe-es6-template
Aalex Gabi

1

Estaba molesto por la redundancia adicional necesario de escribir this.cada vez, por lo que también agregó expresiones regulares para expandir las variables como .aa this.a.

Solución:

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

Utilizar como tal:

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

1

Solo publico un paquete npm que simplemente puede hacer este trabajo. Profundamente inspirado por esta respuesta .

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

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

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

Su implemento es mortalmente simple. Ojalá te guste.


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

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

1

puede usar la función de flecha en línea como esta, definición:

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

uso:

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

1

Cadena de plantilla de tiempo de ejecución

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

Prueba

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

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.