ES6 标记模板实用性
ES6 tagged templates practical usability
我理解ES6的语法tagged templates. What I don't see is the practical usability. When is it better than passing an object parameter, like the settings in jQuery's AJAX? $.ajax('url', { /*this guy here*/ })
现在我只看到了棘手的语法,但我不明白为什么我会 need/use 它。我还发现 TypeScript 团队选择在其他重要功能之前实现它(在 1.5 中)。标记字符串模板背后的概念是什么?
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.
您可以使用标记模板构建比常规函数调用更具表现力的 API。
例如,我正在为 JS 数组上的 SQL 查询开发 proof-of-concept library:
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 - 标记的模板可以插入输入的语言环境敏感版本。
它们很有用,因为该函数可以(几乎)完全定义其中文本的含义(几乎 = 除了占位符)。我喜欢使用 Steven Levithan 的 XRegExp
library 的例子。使用定义为字符串的正则表达式很尴尬,因为您必须对事物进行两次转义:一次用于字符串文字,一次用于正则表达式。这是我们在 JavaScript.
中使用正则表达式文字的原因之一
例如,假设我正在维护一个网站,我发现了这个:
var isSingleUnicodeWord = /^\w+$/;
...这意味着检查一个字符串是否仅包含 "letters." 两个问题:A) \w
在人类语言领域中有成千上万的 "word" 个字符不认识,因为它的定义是以英语为中心的; B) 它包括 _
,许多人(包括 Unicode 联盟)认为这不是 "letter."
假设在我的工作中我已经将 XRegExp
引入了代码库。因为我知道它支持 \pL
(\p
用于 Unicode 类别,L
用于 "letter"),我可能会很快将其换成:
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>
我现在唯一要记住的是 ${...}
很特别,因为它是一个占位符。在这种特定情况下,这不是问题,我不太可能想将量词应用于输入结束断言,但这是巧合...
我理解ES6的语法tagged templates. What I don't see is the practical usability. When is it better than passing an object parameter, like the settings in jQuery's AJAX? $.ajax('url', { /*this guy here*/ })
现在我只看到了棘手的语法,但我不明白为什么我会 need/use 它。我还发现 TypeScript 团队选择在其他重要功能之前实现它(在 1.5 中)。标记字符串模板背后的概念是什么?
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.
您可以使用标记模板构建比常规函数调用更具表现力的 API。
例如,我正在为 JS 数组上的 SQL 查询开发 proof-of-concept library:
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 - 标记的模板可以插入输入的语言环境敏感版本。
它们很有用,因为该函数可以(几乎)完全定义其中文本的含义(几乎 = 除了占位符)。我喜欢使用 Steven Levithan 的 XRegExp
library 的例子。使用定义为字符串的正则表达式很尴尬,因为您必须对事物进行两次转义:一次用于字符串文字,一次用于正则表达式。这是我们在 JavaScript.
例如,假设我正在维护一个网站,我发现了这个:
var isSingleUnicodeWord = /^\w+$/;
...这意味着检查一个字符串是否仅包含 "letters." 两个问题:A) \w
在人类语言领域中有成千上万的 "word" 个字符不认识,因为它的定义是以英语为中心的; B) 它包括 _
,许多人(包括 Unicode 联盟)认为这不是 "letter."
假设在我的工作中我已经将 XRegExp
引入了代码库。因为我知道它支持 \pL
(\p
用于 Unicode 类别,L
用于 "letter"),我可能会很快将其换成:
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>
我现在唯一要记住的是 ${...}
很特别,因为它是一个占位符。在这种特定情况下,这不是问题,我不太可能想将量词应用于输入结束断言,但这是巧合...