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!`);

...让它“更好”。

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


当前回答

我只是发布了一个npm包,它可以简单地完成这项工作。 深受这个答案的启发。

const Template = require('dynamic-template-string');

var tpl = new Template('hello ${name}');

tpl.fill({name: 'world'}); // ==> 'hello world';
tpl.fill({name: 'china'}); // ==> 'hello china';

它的实现非常简单。希望你会喜欢。


module.exports = class Template {
  constructor(str) {
    this._func = new Function(`with(this) { return \`${str}\`; }`);
  }

  fill(data) {
    return this._func.call(data);
  }
}

其他回答

2019答:

注意:标准库最初希望用户清理字符串以避免XSS。库的版本2不再要求净化用户字符串(web开发人员无论如何都应该这样做),因为它完全避免了eval。

npm上的es6-dynamic-template模块可以做到这一点。

const fillTemplate = require('es6-dynamic-template');

与目前的答案不同:

它使用ES6模板字符串,而不是类似的格式。更新版本2使用类似的格式,而不是ES6模板字符串,以防止用户使用未经消毒的输入字符串。 模板字符串中不需要这个 可以在单个函数中指定模板字符串和变量 它是一个维护的,可更新的模块,而不是从StackOverflow复制

使用方法很简单。使用单引号作为模板字符串将在稍后解决!

const greeting = fillTemplate('Hi ${firstName}', {firstName: 'Joe'});

如果你正在寻找一些相当简单的东西(只是固定的变量字段,没有计算,条件…),但这也适用于没有模板字符串支持的浏览器客户端,如IE 8,9,10,11…

开始吧:

fillTemplate = function (templateString, templateVars) {
    var parsed = templateString;
    Object.keys(templateVars).forEach(
        (key) => {
            const value = templateVars[key]
            parsed = parsed.replace('${'+key+'}',value)
        }
    )
    return parsed
}

2021年出现了迄今为止最直接的解决方案。

const tl = $ =>`This ${$.val}`;
tl({val: 'code'});

这几乎等同于仅仅编写和重用模板文字(OP想要的)。

你可以从这里开始调整……

你可以在函数中放入一个模板字符串:

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”中分离出常量字符串,然后返回一个函数,该函数每次都根据一组新的值将它们重新组合在一起。

可能最干净的方法是使用箭头函数(因为在这一点上,我们已经在使用ES6)

var reusable = () => `This ${object} was created by ${creator}`;

var object = "template string", creator = "a function";
console.log (reusable()); // "This template string was created by a function"

object = "example", creator = "me";
console.log (reusable()); // "This example was created by me"

...对于带标签的模板字面量:

reusable = () => myTag`The ${noun} go ${verb} and `;

var noun = "wheels on the bus", verb = "round";
var myTag = function (strings, noun, verb) {
    return strings[0] + noun + strings[1] + verb + strings[2] + verb;
};
console.log (reusable()); // "The wheels on the bus go round and round"

noun = "racecars", verb = "fast";
myTag = function (strings, noun, verb) {
    return strings[0] + noun + strings[1] + verb;
};
console.log (reusable()); // "The racecars go fast"

这也避免了eval()或Function()的使用,这可能会导致编译器出现问题,并导致大量的放缓。