是否可以创建一个模板字符串作为一个普通的字符串,
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和其他动态代码生成的手段?
当前回答
仍然是动态的,但似乎比使用裸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
其他回答
我提出了这个实现,它的工作就像一个魅力。
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,可能会引发错误
你想要的是:
//从问题中引用的非工作代码 让b = 10; console.log (a.template ()); / / b: 10
与eval完全相同(就功能和安全而言):获取包含代码的字符串并执行该代码的能力;执行的代码还可以看到调用者环境中的局部变量。
在JS中,函数无法看到调用者中的局部变量,除非该函数是eval()。甚至Function()也做不到。
当您听说JavaScript中出现了所谓的“模板字符串”时,很自然地认为这是一个内置的模板库,就像Mustache一样。它不是。它主要是字符串插值和JS的多行字符串。不过,我认为这在一段时间内将是一个普遍的误解。:(
我目前不能评论现有的答案,所以我无法直接评论布莱恩·雷诺的出色回答。因此,这个回答将会更新他的答案,稍微修正一下。
简而言之,他的函数实际上没有缓存创建的函数,所以它总是重新创建,不管之前是否见过模板。以下是修正后的代码:
/**
* Produces a function which uses template strings to do simple interpolation from objects.
*
* Usage:
* var makeMeKing = generateTemplateString('${name} is now the king of ${country}!');
*
* console.log(makeMeKing({ name: 'Bryan', country: 'Scotland'}));
* // Logs 'Bryan is now the king of Scotland!'
*/
var generateTemplateString = (function(){
var cache = {};
function generateTemplate(template){
var fn = cache[template];
if (!fn){
// Replace ${expressions} (etc) with ${map.expressions}.
var sanitized = template
.replace(/\$\{([\s]*[^;\s\{]+[\s]*)\}/g, function(_, match){
return `\$\{map.${match.trim()}\}`;
})
// Afterwards, replace anything that's not ${map.expressions}' (etc) with a blank string.
.replace(/(\$\{(?!map\.)[^}]+\})/g, '');
fn = cache[template] = Function('map', `return \`${sanitized}\``);
}
return fn;
};
return generateTemplate;
})();
我喜欢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
)
);
}
因为我们正在重新发明一些东西,这将是javascript中的一个可爱的特性。
我使用eval(),这是不安全的,但javascript是不安全的。我承认我不擅长javascript,但我有一个需求,我需要一个答案,所以我做了一个。
我选择用@而不是$来风格化我的变量,特别是因为我想使用文字的多行特性,直到它准备好才计算。变量语法是@{optionalobject。optionalobjectn。variable_name}
我不是javascript专家,所以我很乐意听取改进建议,但是……
var prsLiteral, prsRegex = /\@\{(.*?)(?!\@\{)\}/g
for(i = 0; i < myResultSet.length; i++) {
prsLiteral = rt.replace(prsRegex,function (match,varname) {
return eval(varname + "[" + i + "]");
// you could instead use return eval(varname) if you're not looping.
})
console.log(prsLiteral);
}
下面是一个非常简单的实现
myResultSet = {totalrecords: 2, 姓名:["Bob", "Stephanie"], 37岁的年龄:[22]}; rt = '我的名字是@{myResultSet。我是@{myResultSet.Age}。' var prsLiteral, prsRegex = /\@\{(.*?)(?!\@\{)\}/g . var prsLiteral, prsRegex = /\@\ For (i = 0;i < myResultSet.totalrecords;我+ +){ prsLiteral = rt.replace(prsRegex,函数(匹配,varname) { 返回eval(varname + "[" + I + "]"); //如果不循环,可以使用return eval(varname)。 }) console.log (prsLiteral); }
在我的实际实现中,我选择使用@{{variable}}。再来一组大括号。不太可能意外地遇到这种情况。的正则表达式 /\@\{\{(.*?)(?!\@\{\{)\}\}/ g
为了便于阅读
\@\{\{ # opening sequence, @{{ literally.
(.*?) # capturing the variable name
# ^ captures only until it reaches the closing sequence
(?! # negative lookahead, making sure the following
# ^ pattern is not found ahead of the current character
\@\{\{ # same as opening sequence, if you change that, change this
)
\}\} # closing sequence.
如果您对正则表达式没有经验,一个非常安全的规则是转义每个非字母数字字符,并且不要不必要地转义字母,因为许多转义字母对于几乎所有类型的正则表达式都具有特殊意义。