是否可以创建一个模板字符串作为一个普通的字符串,
let a = "b:${b}";
然后把它转换成一个模板字符串,
let b = 10;
console.log(a.template()); // b:10
没有eval, new Function和其他动态代码生成的手段?
是否可以创建一个模板字符串作为一个普通的字符串,
let a = "b:${b}";
然后把它转换成一个模板字符串,
let b = 10;
console.log(a.template()); // b:10
没有eval, new Function和其他动态代码生成的手段?
当前回答
有很多好的解决方案张贴在这里,但没有一个利用ES6字符串。原始的方法。这是我的贡献。它有一个重要的限制,它只接受传入对象的属性,这意味着模板中的代码执行将不起作用。
function parseStringTemplate(str, obj) {
let parts = str.split(/\$\{(?!\d)[\wæøåÆØÅ]*\}/);
let args = str.match(/[^{\}]+(?=})/g) || [];
let parameters = args.map(argument => obj[argument] || (obj[argument] === undefined ? "" : obj[argument]));
return String.raw({ raw: parts }, ...parameters);
}
let template = "Hello, ${name}! Are you ${age} years old?";
let values = { name: "John Doe", age: 18 };
parseStringTemplate(template, values);
// output: Hello, John Doe! Are you 18 years old?
将字符串拆分为非参数的文本部分。看到正则表达式。 部分:[“你好,”,“!”你多大了?”) 将字符串拆分为属性名。如果匹配失败则为空数组。 参数:["name", "age"] 通过属性名映射obj中的参数。解决方案受限于浅的一级映射。未定义的值用空字符串代替,但接受其他假值。 参数:["John Doe", 18] 使用String.raw(…)并返回结果。
其他回答
你想要的是:
//从问题中引用的非工作代码 让b = 10; console.log (a.template ()); / / b: 10
与eval完全相同(就功能和安全而言):获取包含代码的字符串并执行该代码的能力;执行的代码还可以看到调用者环境中的局部变量。
在JS中,函数无法看到调用者中的局部变量,除非该函数是eval()。甚至Function()也做不到。
当您听说JavaScript中出现了所谓的“模板字符串”时,很自然地认为这是一个内置的模板库,就像Mustache一样。它不是。它主要是字符串插值和JS的多行字符串。不过,我认为这在一段时间内将是一个普遍的误解。:(
仍然是动态的,但似乎比使用裸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
我喜欢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+'`');
我提出了这个实现,它的工作就像一个魅力。
function interpolateTemplate(template: string, args: any): string {
return Object.entries(args).reduce(
(result, [arg, val]) => result.replace(`$\{${arg}}`, `${val}`),
template,
)
}
const template = 'This is an example: ${name}, ${age} ${email}'
console.log(interpolateTemplate(template,{name:'Med', age:'20', email:'example@abc.com'}))
如果在模板中没有找到arg,可能会引发错误