ES6标记模板的实际用途

13

我理解ES6 标签模板 的语法,但我没有看到它的实际用途。什么情况下会比传递一个对象参数更好,例如jQuery的AJAX中的设置,像这样:$.ajax('url', { /*这个家伙*/ })

目前我只看到了棘手的语法,但我不知道为什么我需要/使用它。我还发现TypeScript团队在实现其他重要功能之前选择了它(在1.5中)。标记字符串模板背后的概念是什么?


1
你的链接中说的是什么(但也许我误解了你的意图):“使用它们,您可以使用函数修改模板字符串的输出。” - SPRBRN
是的,你说得没错。但这是否值得引入一个全新且有点棘手的语言元素呢?我宁愿用普通的JS函数来实现,这样更简单,也不需要太多的努力。--编辑:我的意思是我会通过POJS功能来实现它。(一个单独的函数可能不足够。) - Gábor Imre
4
我想好处在于可以控制语义,它不必执行字符串插入。我使用标记模板使其易于插值和创建AST节点:https://github.com/facebook/jscodeshift/blob/f866c37e7ff7d1a324c2968e571b5ffb7928eb93/src/__tests__/template-test.js#L58-L64。当然,也可以用其他方法解决这个问题,但可能没有这种方法简洁易读。 - Felix Kling
我猜这个功能主要是针对框架开发人员的。(Angular2?React?)我开始看到它的意义,但这不是典型的工业项目开发,而是一些强大的低级数据修改。 - Gábor Imre
3个回答

10
你可以使用带标签的模板来构建比常规函数调用更具表现力的API。
例如,我正在为JS数组上的SQL查询工作的概念库进行概念验证
let admins = sql`SELECT name, id FROM ${users} 
                 WHERE ${user => user.roles.indexOf('admin') >= 0}`

请注意,这与字符串插值无关;它使用带标签的模板以提高可读性。如果使用普通函数调用来构造类似直观的结果会很困难 - 我猜你会得到类似这样的结果:

let admins = sql("SELECT name, id FROM $users WHERE $filter",
  { $users: users, $filter: (user) => user.roles.contains('admin') })

这个例子只是一个有趣的副业项目,但我认为它展示了标记模板的一些好处。

另一个更明显的例子是i18n——标记模板可以插入本地化敏感版本的输入。


8

请参考Sitepoint的解释

The final stage of template strings specification is about adding a custom function before the string itself to create a tagged template string.

...

For instance, here is a piece of code to block strings that try to inject custom DOM elements:

var items = [];
items.push("banana");
items.push("tomato");
items.push("light saber");
var total = "Trying to hijack your site <BR>";
var myTagFunction = function (strings,...values) {
  var output = "";
  for (var index = 0; index < values.length; index++) {
    var valueString = values[index].toString();

    if (valueString.indexOf(">") !== -1) {
      // Far more complex tests can be implemented here :)
      return "String analyzed and refused!";
    }

    output += strings[index] + values[index];
  }

  output += strings[index]
  return output;
}

result.innerHTML = myTagFunction `You have ${items.length} item(s) in your basket for a total of $${total}`;

Tagged template strings can used for a lot of things like security, localization, creating your own domain specific language, etc.


4

它们很有用,因为函数(几乎)可以完全定义其中的文本含义(“几乎”指占位符以外的内容)。我喜欢使用 Steven Levithan 的 XRegExp 作为例子。将正则表达式定义为字符串使用起来很笨拙,因为你必须进行双重转义:一次是为了字符串面值,另一次是为了正则表达式。这就是 JavaScript 中具有正则表达式字面量的原因之一。

例如,假设我正在维护一个网站并发现以下内容:

var isSingleUnicodeWord = /^\w+$/;

这段代码旨在检查一个字符串是否仅包含“字母”。但有两个问题:A) 在人类语言领域中有数千个“单词”字符,\w无法识别,因为其定义是以英语为中心的; B) 它包括_,许多人(包括Unicode联盟)认为它不是“字母”。

假设在我的工作中,我已经将XRegExp引入到代码库中。由于我知道它支持\pL(\p用于Unicode类别,L表示“字母”),我可能会迅速地进行替换:

var isSingleUnicodeWord = XRegExp("^\pL+$"); // WRONG

然后我想知道为什么它没有起作用,*扇耳光*,回去转义那个反斜杠,因为它被字符串字面量消耗了:

var isSingleUnicodeWord = XRegExp("^\\pL+$");
// ---------------------------------^

真是太麻烦了。如果我能写实际的正则表达式而不用担心双重转义怎么办呢?

我可以:通过一个标记模板函数。我可以将其放在我的标准库中:

function xrex(strings, ...values) {
    const raw = strings.raw;
    let result = "";
    for (let i = 0; i < raw.length; ++i) {
        result += raw[i];
        if (i < values.length) { // `values` always has one fewer entry
            result += values[i];
        }
    }
    return XRegExp(result);
}

或者,这是一个reduce的有效用例,我们可以在参数列表中使用解构:

function xrex({raw}, ...values) {
    return XRegExp(
        raw.reduce(
            (acc, str, index) => acc + str + (index < values.length ? values[index] : ""),
            ""
        )
    );
}

然后我就可以愉快地写下:

const isSingleUnicodeWord = xrex`^\pL+$`;

例子:

// My tag function (defined once, then reused)
function xrex({raw}, ...values) {
    const result = raw.reduce(
        (acc, str, index) => acc + str + (index < values.length ? values[index] : ""),
        ""
    );
    console.log("Creating with:", result);
    return XRegExp(result);
}

// Using it, with a couple of substitutions to prove to myself they work
let category = "L";                // L: Letter
let maybeEol = "$";
let isSingleUnicodeWord = xrex`^\p${category}+${maybeEol}`;
function test(str) {
    console.log(str + ": " + isSingleUnicodeWord.test(str));
}
test("Русский");  // true
test("日本語");    // true
test("العربية");  // true
test("foo bar");  // false
test("$£");       // false
<script src="https://cdnjs.cloudflare.com/ajax/libs/xregexp/3.2.0/xregexp-all.min.js"></script>

现在我需要记住的唯一一件事就是,${...}是特殊的,因为它是一个占位符。在这种特定情况下,这不是问题,我不太可能想要将量词应用于输入结尾的断言,但这只是巧合...

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接