ES6标记模板实用性

时间:2015-07-23 14:54:06

标签: javascript ecmascript-6 template-strings tagged-templates

我理解ES6 tagged templates的语法。我看不到的是实用性。什么时候比传递一个对象参数更好,比如jQuery's AJAX中的设置? $.ajax('url', { /*this guy here*/ })

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

3 个答案:

答案 0 :(得分:8)

请参阅Sitepoint's explanation

  

模板字符串规范的最后阶段是在字符串本身之前添加自定义函数以创建标记模板字符串。

     

...

     

例如,这里有一段代码来阻止尝试注入自定义DOM元素的字符串:

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}`;
     

标记的模板字符串可用于许多内容,如安全性,本地化,创建自己的特定于域的语言等。

答案 1 :(得分:8)

您可以使用标记模板来构建比常规函数调用更具表现力的API。

例如,我正在使用proof-of-concept library对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 - 标记模板可以插入输入的区域设置敏感版本。

答案 2 :(得分:3)

它们很有用,因为函数可以(几乎)完全定义其中文本的含义(几乎=占位符除外)。我喜欢用Steven Levithan的XRegExp library的例子。使用定义为字符串的正则表达式很尴尬,因为你必须双重转义:一次是字符串文字,一次是正则表达式。这是我们在JavaScript中使用正则表达式文字的原因之一。

例如,假设我在网站上进行维护,我发现了这个:

var isSingleUnicodeWord = /^\w+$/;

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

假设在我的工作中我已将XRegExp引入代码库。因为我知道它支持\pL\p用于Unicode类别,L用于“字母”),我可以快速交换它:

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

然后我想知道为什么它不起作用,* facepalm *,然后回去逃避反斜杠,因为它被字符串文字消耗了:

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>

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