我理解ES6 标签模板 的语法,但我没有看到它的实际用途。什么情况下会比传递一个对象参数更好,例如jQuery的AJAX中的设置,像这样:$.ajax('url', { /*这个家伙*/ })
目前我只看到了棘手的语法,但我不知道为什么我需要/使用它。我还发现TypeScript团队在实现其他重要功能之前选择了它(在1.5中)。标记字符串模板背后的概念是什么?
我理解ES6 标签模板 的语法,但我没有看到它的实际用途。什么情况下会比传递一个对象参数更好,例如jQuery的AJAX中的设置,像这样:$.ajax('url', { /*这个家伙*/ })
目前我只看到了棘手的语法,但我不知道为什么我需要/使用它。我还发现TypeScript团队在实现其他重要功能之前选择了它(在1.5中)。标记字符串模板背后的概念是什么?
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——标记模板可以插入本地化敏感版本的输入。
请参考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.
它们很有用,因为函数(几乎)可以完全定义其中的文本含义(“几乎”指占位符以外的内容)。我喜欢使用 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>
${...}
是特殊的,因为它是一个占位符。在这种特定情况下,这不是问题,我不太可能想要将量词应用于输入结尾的断言,但这只是巧合...