31

Say I have a variable str

var str = "123"

Now I could do console.log(`Hello ${str}`) and it will print Hello 123

Now I have another variable strnew

var strnew = 'Hello ${str}'

Note (based on answers/comments) - strnew is read from a file, so its always a string and cant be replaced with `

How do I console.log(...) to print Hello 123

Is it possible wihtout any kind of eval()

Faiz Mohamed Haneef
  • 3,418
  • 4
  • 31
  • 41

4 Answers4

35

With something as simple as ${str} you can use a simple string replacement:

var template = (tpl, args) => tpl.replace(/\${(\w+)}/g, (_, v) => args[v]);

var tpl = 'Hello ${str} and ${other}';

console.log(template(tpl, {str: 'foo', other: 'bar'}));

In a general case, no, not possible without eval (short of writing your own js interpreter), because ${...} can contain arbitrary expressions.

For completeness' sake, here's the eval solution:

var template = function(tpl, args) {
    var keys = Object.keys(args),
        fn = new Function(...keys, 
          'return `' + tpl.replace(/`/g, '\\`') + '`');
    return fn(...keys.map(x => args[x]));
};


function test() {
    var myTpl = 'Hello ${str + "!"} and ${other.toUpperCase()}';
    console.log(template(myTpl, {str: 'foo', other: 'bar'}));
}

test();
georg
  • 211,518
  • 52
  • 313
  • 390
  • I'm very sorry, I edited your post instead of suggesting an edit, but I reverted it. new Function('', 'return `' + tpl + '`'); could be optimized to new Function('return `' + tpl + '`'); – Lyubomir Dec 13 '16 at 10:30
  • Great answer!! This should be the accepted answer. Give me a day or two to confirm. – Faiz Mohamed Haneef Dec 13 '16 at 11:07
  • 1
    _`template(myTpl, str='foo', other='bar')`_ this code implicitly creates two global variables. Argumants passed to the function are never used. – Qwertiy Sep 26 '17 at 12:13
  • 1
    @Qwertiy: right-o, too much python recently ;) fixed. – georg Sep 26 '17 at 12:24
1

You can use function instead of just string.

var strnew = function(str){
  return `Hello ${str}`;
}
var str = "123";
console.log(strnew(str))
Dmitry Masley
  • 525
  • 4
  • 9
0

Thanks to this answer, here is a bit of black magic code that achieves what you want. Disclaimer - this is for fun / very limited and exotic application. It is likely to be very slow and break down on lots of edge cases, but with a limited scope of your question it works.

function getString(){
 return "calculating ${foo} + ${bar} = ${foo + bar}";
}

var localEnvironmentProxy = new Proxy({}, {
    has(target, prop) { return true; },
    get(target, prop) { return (prop in target ? target : window)[prop]; }
  });
  
  with(localEnvironmentProxy){
  
 var foo = 1;
 var bar = 2;
  
 var templString = getString();
 
 var fnFullText = 'with(arguments[0]){ return `' + templString + '`;}';
 
 var tempalteFn = new Function(fnFullText);
    
 console.log(tempalteFn(localEnvironmentProxy));
    //calculating 1 + 2 = 3
  
  }
Ivan Koshelev
  • 3,830
  • 2
  • 30
  • 50
0

I built off of @georg's answer above for a typescript solution:

public renderTemplate(templateStr: string, args: any): string {
  templateStr = templateStr.replace(/`/g, '\\`');
  
  const keys = Object.keys(args);

  const fn = new Function(...keys, 'return `' + templateStr + '`');

  return fn(...keys.map(key => args[key]));
}

The usage is virtually the same as well.

Kurtis Jungersen
  • 2,204
  • 1
  • 26
  • 31