ES6 模板文本是否可以在运行时替换(或重用)?

tl;dr:是否有可能制作一个可重用的模板文字?

我一直在尝试使用模板文字,但我想我只是不明白,现在我感到沮丧。我的意思是,我想我明白了,但“它”不应该是它的工作方式,或者它应该如何得到。它应该变得不同。

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

每个人都举了一个可怕的例子,类似于:

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

这很好,但如果我已经知道,我会只是或.有什么意义?认真地。好吧,重点是懒惰;更少的优点,更高的可读性。伟大。但这不是一个模板!恕我直言,不是。而MHO才是最重要的!恕我直言,问题在于模板在声明时会被评估,因此,如果您这样做,恕我直言:areturn 'Worthless asd'return 'Worthless '+a

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

由于 未声明,因此它输出类似 的内容。超。实际上,至少在Chrome中,我甚至无法声明模板;它抛出错误,因为 未定义。我需要的是能够在声明模板后进行替换:expletiveMy undefined templateexpletive

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。我想“字面”部分应该给我小费(如in,不可变)?

我错过了什么吗?有没有一种(好的)方法来制作可重用的模板文字?


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

> 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!

这是一个幼稚的“助手”功能...

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

...使其“更好”。

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


答案 1

要使这些文字像其他模板引擎一样工作,需要一个中间形式。

执行此操作的最佳方法是使用构造函数。Function

const templateString = "Hello ${this.name}!";
const templateVars = {
    name: "world"    
}

const fillTemplate = function(templateString, templateVars){
    return new Function("return `"+templateString +"`;").call(templateVars);
}

console.log(fillTemplate(templateString, templateVars));

与其他模板引擎一样,您可以从其他位置(如文件)获取该字符串。

使用此方法可能会出现一些问题(例如,添加模板标记会比较困难)。你也不能有内联的JavaScript逻辑,因为插值很晚。这也可以通过一些思考来补救。


答案 2

您可以将模板字符串放在函数中:

function reusable(a, b) {
  return `a is ${a} and b is ${b}`;
}

您可以对标记的模板执行相同的操作:

function reusable(strings) {
  return function(... vals) {
    return strings.map(function(s, i) {
      return `${s}${vals[i] || ""}`;
    }).join("");
  };
}

var tagged = reusable`a is ${0} and b is ${1}`; // dummy "parameters"
console.log(tagged("hello", "world"));
// prints "a is hello b is world"
console.log(tagged("mars", "jupiter"));
// prints "a is mars b is jupiter"

这个想法是让模板解析器从变量“slots”中分离出常量字符串,然后返回一个函数,该函数每次根据一组新值将其全部修补在一起。