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

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

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

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

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


当前回答

我喜欢s.m ijer的回答,并在他的基础上写了自己的版本:

function parseTemplate(template, map, fallback) {
    return template.replace(/\$\{[^}]+\}/g, (match) => 
        match
            .slice(2, -1)
            .trim()
            .split(".")
            .reduce(
                (searchObject, key) => searchObject[key] || fallback || match,
                map
            )
    );
}

其他回答

由于模板字符串必须动态地(在运行时)获得对b变量的引用,所以答案是:不,没有动态代码生成是不可能做到的。

但是,使用eval非常简单:

let tpl = eval('`'+a+'`');

仍然是动态的,但似乎比使用裸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 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));

在我的项目中,我用ES6创建了这样的东西:

String.prototype.interpolate =函数(参数){ const names = Object.keys(params); const vals = Object.values(params); 返回新功能(…的名字,‘返回’$ { }\`;`)(... 瓦尔斯); } const template = '示例文本:${text}'; Const result = template.interpolate({ 文本:“Foo Boo” }); console.log(结果);

类似于Daniel的回答(以及s.m ijer的要点),但更易于阅读:

const regex = /\${[^{]+}/g;

export default function interpolate(template, variables, fallback) {
    return template.replace(regex, (match) => {
        const path = match.slice(2, -1).trim();
        return getObjPath(path, variables, fallback);
    });
}

//get the specified property or nested property of an object
function getObjPath(path, obj, fallback = '') {
    return path.split('.').reduce((res, key) => res[key] || fallback, obj);
}

注意:这稍微改进了s.m ijer的原始版本,因为它不会匹配像${foo{bar}这样的东西(正则表达式只允许${和}内的非花括号字符)。


更新:我被要求使用这个例子,所以你去:

const replacements = {
    name: 'Bob',
    age: 37
}

interpolate('My name is ${name}, and I am ${age}.', replacements)