概述
JavaScript 中的模板字面量标签函数(Tagged Template Literals)是 ES6 引入的一个强大特性。它允许你通过自定义函数解析模板字符串(用反引号 ` 包裹的字符串),从而更灵活地处理字符串拼接和插值逻辑。
核心概念
1. 基本语法
模板标签函数是一个普通函数,通过在模板字符串前直接调用(无需括号)来使用:
const result = myTag`Hello ${name}!`;
// 等价于调用函数: myTag(["Hello ", "!"], name)
2. 参数解析
标签函数接收以下参数:
strings:模板字符串的静态部分组成的数组。- 例如,模板字符串
`A ${1} B ${2} C`对应的strings是["A ", " B ", " C"]。
- 例如,模板字符串
...values:所有插值表达式(${...})的值,按顺序作为剩余参数传递。- 对应上述例子,
values是[1, 2]。
- 对应上述例子,
3. 函数返回值
标签函数可以返回任意类型的值,不一定是字符串。这使得它可以用于生成数据结构(如对象、DOM 节点等)。
示例代码
示例 1:简单大写转换
function upperTag(strings, ...values) {
// 将插值部分转为大写
const processed = values.map(value => String(value).toUpperCase());
// 拼接静态字符串和处理后的插值
let result = strings[0];
for (let i = 0; i < processed.length; i++) {
result += processed[i] + strings[i + 1];
}
return result;
}
const name = "Alice";
const age = 25;
console.log(upperTag`Hello ${name}, you are ${age}.`);
// 输出: "Hello ALICE, you are 25."
示例 2:HTML 安全转义(防 XSS)
function safeHTML(strings, ...values) {
let result = strings[0];
for (let i = 0; i < values.length; i++) {
// 转义特殊字符
const escaped = String(values[i])
.replace(/&/g, "&")
.replace(/</g, "<")
.replace(/>/g, ">");
result += escaped + strings[i + 1];
}
return result;
}
const userInput = "<script>alert('hack')</script>";
const html = safeHTML`<div>${userInput}</div>`;
console.log(html); // 输出: <div><script>alert('hack')</script></div>
应用场景
-
国际化(i18n)
根据语言动态替换模板中的占位符:i18n`Welcome, ${userName}! You have ${unreadCount} messages.`; -
样式化组件(如 styled-components)
生成带有作用域样式的 React 组件:const Button = styled.button` background: ${props => props.primary ? "blue" : "gray"}; color: white; `; -
GraphQL 查询构建
清理或优化查询语句:const query = gql` user(id: ${id}) { name email } `; -
自定义 DSL(领域特定语言)
解析模板字符串为特定数据结构(如 SQL 查询):const sql = SQL` SELECT * FROM users WHERE name = ${name} `;
高级用法
原始字符串(Raw Strings)
通过 strings.raw 可以访问未转义的原始字符串(例如保留 \n 而非实际换行):
function rawTag(strings) {
console.log(strings.raw[0]); // 输出原始字符,如包含 \n
}
rawTag`Hello\nWorld`; // 输出 "Hello\\nWorld"
返回非字符串值
标签函数可以返回任意类型,如生成 DOM 元素:
function link(strings, ...values) {
const url = values[0];
const text = strings[1];
return `<a href="${url}">${text}</a>`;
}
const element = link`Visit ${"https://example.com"} our site!`;
关键注意点
strings和values的长度关系
strings的长度始终是values.length + 1。- 性能考量
复杂的标签函数可能影响性能,需谨慎使用。 - 表达式求值顺序
插值表达式在传入标签函数前已完成求值。
总结
掌握标签函数后,你可以更灵活地控制字符串生成逻辑,适用于库开发、模板引擎等高级场景。