是否可以创建一个模板字符串作为一个普通的字符串,

let a = "b:${b}";

然后把它转换成一个模板字符串,

let b = 10;
console.log(a.template()); // b:10

没有eval, new Function和其他动态代码生成的手段?


当前回答

仍然是动态的,但似乎比使用裸eval更可控:

const vm = require('vm')
const moment = require('moment')


let template = '### ${context.hours_worked[0].value} \n Hours worked \n #### ${Math.abs(context.hours_worked_avg_diff[0].value)}% ${fns.gt0(context.hours_worked_avg_diff[0].value, "more", "less")} than usual on ${fns.getDOW(new Date())}'
let context = {
  hours_worked:[{value:10}],
  hours_worked_avg_diff:[{value:10}],

}


function getDOW(now) {
  return moment(now).locale('es').format('dddd')
}

function gt0(_in, tVal, fVal) {
  return _in >0 ? tVal: fVal
}



function templateIt(context, template) {
  const script = new vm.Script('`'+template+'`')
  return script.runInNewContext({context, fns:{getDOW, gt0 }})
}

console.log(templateIt(context, template))

https://repl.it/IdVt/3

其他回答

我知道我来晚了,但你可以:

Const a = (b) => ' b:${b} '; 令b = 10; console.log (a (b));/ / b: 10

@Mateusz Moska,解决方案很好,但当我在React Native(构建模式)中使用它时,它抛出一个错误:无效字符'”,尽管当我在调试模式下运行它时它是有效的。

所以我用正则表达式写出了我自己的解。

String.prototype.interpolate = function(params) {
  let template = this
  for (let key in params) {
    template = template.replace(new RegExp('\\$\\{' + key + '\\}', 'g'), params[key])
  }
  return template
}

const template = 'Example text: ${text}',
  result = template.interpolate({
    text: 'Foo Boo'
  })

console.log(result)

演示:https://es6console.com/j31pqx1p/

注:因为我不知道问题的根本原因,我在react-native repo中提出了一张票,https://github.com/facebook/react-native/issues/14107,这样一旦他们能够修复/指导我大致相同:)

您可以参考这个解决方案 Const interpolate = (str) => new Function(' return \ ' ${new String(str)}\ '; ')(); const foo = 'My'; Const obj = { 文本:汉尼拔·莱克特 firstNum: 1、 secondNum: 2 } Const STR = "${foo}名称为:${obj.text}。Sum = ${obj。firstNum} + ${obj。secondNum} = ${obj。firstNum + obj.secondNum}"; console.log(插入(str));

我需要Internet Explorer支持这种方法。事实证明,甚至连IE11都不支持后勾。也;使用eval或它的等效函数感觉不对。

为了那个注意到的人;我也使用反撇号,但是这些被像babel这样的编译器删除了。其他方法建议的方法取决于运行时。如前所述;这是IE11及以下版本的问题。

这就是我想到的:

function get(path, obj, fb = `$\{${path}}`) {
  return path.split('.').reduce((res, key) => res[key] || fb, obj);
}

function parseTpl(template, map, fallback) {
  return template.replace(/\$\{.+?}/g, (match) => {
    const path = match.substr(2, match.length - 3).trim();
    return get(path, map, fallback);
  });
}

示例输出:

const data = { person: { name: 'John', age: 18 } };

parseTpl('Hi ${person.name} (${person.age})', data);
// output: Hi John (18)

parseTpl('Hello ${person.name} from ${person.city}', data);
// output: Hello John from ${person.city}

parseTpl('Hello ${person.name} from ${person.city}', data, '-');
// output: Hello John from -

这里的问题是有一个函数可以访问它的调用者的变量。这就是为什么我们看到直接eval被用于模板处理。一种可能的解决方案是生成一个函数,接受由字典属性命名的形式参数,并以相同的顺序使用相应的值调用它。另一种方法是这样简单:

var name = "John Smith";
var message = "Hello, my name is ${name}";
console.log(new Function('return `' + message + '`;')());

对于任何使用Babel编译器的人,我们需要创建一个闭包,它可以记住创建它的环境:

console.log(new Function('name', 'return `' + message + '`;')(name));