是否可以像通常的字符串一样创建模板字符串,
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 创建了这样的东西:
String.prototype.interpolate = function(params) {
const names = Object.keys(params);
const vals = Object.values(params);
return new Function(...names, `return \`${this}\`;`)(...vals);
}
const template = 'Example text: ${text}';
const result = template.interpolate({
text: 'Foo Boo'
});
console.log(result);
由于您的模板字符串必须b
动态地(在运行时)获得对变量的引用,所以答案是:不,如果没有动态代码生成,就不可能做到这一点。
但是,eval
它非常简单:
let tpl = eval('`'+a+'`');
不,没有动态代码生成就没有办法做到这一点。
但是,我创建了一个函数,该函数将在内部使用模板字符串将常规字符串转换为可以提供值映射的函数。
/**
* 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 = Function('map', `return \`${sanitized}\``);
}
return fn;
}
return generateTemplate;
})();
用法:
var kingMaker = generateTemplateString('${name} is king!');
console.log(kingMaker({name: 'Bryan'}));
// Logs 'Bryan is king!' to the console.
希望这可以帮助某人。如果您发现代码有问题,请及时更新 Gist。
你在这里要求的是:
//non working code quoted from the question let b=10; console.log(a.template());//b:10
完全等同于(就功率而言,呃,安全性)eval
:获取包含代码的字符串并执行该代码的能力;以及执行代码在调用者环境中查看局部变量的能力。
在 JS 中,函数无法在其调用者中查看局部变量,除非该函数是eval()
. 甚至Function()
做不到。
当您听说 JavaScript 中有一种叫做“模板字符串”的东西时,很自然地会假设它是一个内置的模板库,比如 Mustache。不是。它主要只是用于 JS 的字符串插值和多行字符串。不过,我认为这将是一段时间内的普遍误解。:(
这里发布了许多很好的解决方案,但还没有一个使用ES6 String.raw 方法。这是我的贡献。它有一个重要的限制,它只接受来自传入对象的属性,这意味着模板中的任何代码都不会执行。
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?
parts: ["Hello, ", "! Are you ", " years old?"]
args: ["name", "age"]
obj
按属性名称映射参数。解决方案受浅一级映射的限制。未定义的值被替换为空字符串,但也接受其他虚假值。parameters: ["John Doe", 18]
String.raw(...)
并返回结果。