模板字符串
ES6 用反引号表示的字符串语法,支持插值、多行和标签模板。
#type / concept
#status / growing
#resource / javascript
#resource / ecmascript
[!info] related notes
- 所属 MOC: ES6 新特性 MOC, ECMAScript MOC
- 前置概念: JavaScript / TypeScript 字符串方法
- 并列概念: ECMAScript语法基础
模板字符串
一句话定义
模板字符串(Template Literals)是 ES6 引入的字符串字面量语法,用反引号 ` 包裹,支持 ${} 表达式插值、多行文本和标签模板(Tagged Templates)。
核心机制 / 工作原理
基本用法:插值与多行
const name = 'Tom'
const age = 18
// 插值:${} 内可以放任意表达式
const text = `hello, ${name}, age ${age + 1}`
// 多行:反引号内直接换行
const html = `
<div>
<p>Hello, ${name}</p>
</div>
`
${} 内不只是变量名,可以是任意表达式:
const price = 99
const msg = `总价: $${price * 0.8}` // 表达式、函数调用都可以
标签模板(Tagged Templates)
标签模板是模板字符串的高级形式:在模板字符串前放一个函数名,该函数接收模板的静态部分和动态值:
function highlight(strings, ...values) {
// strings: 静态字符串数组 ['', ' is ', ' years old']
// values: 插值结果数组 ['Tom', 18]
return strings.reduce((result, str, i) => {
return result + str + (values[i] !== undefined ? `<b>${values[i]}</b>` : '')
}, '')
}
const html = highlight`Tom is 18 years old`
// "<b>Tom</b> is <b>18</b> years old"
标签模板的本质:函数调用。模板字符串前的函数名是标签(tag),它接收并处理模板内容。
最小例子
// 普通拼接
const old = 'Hello, ' + name + '!' + '\\n' + 'Welcome.'
// 模板字符串
const modern = `Hello, ${name}!
Welcome.`
// 标签模板:自动转义 HTML
function safeHTML(strings, ...values) {
return strings.reduce((result, str, i) => {
const val = values[i] !== undefined
? String(values[i]).replace(/&/g, '&').replace(/</g, '<')
: ''
return result + str + val
}, '')
}
const userInput = '<script>alert("xss")</script>'
const safe = safeHTML`User said: ${userInput}`
// "User said: <script>alert("xss")</script>"
实际应用
HTML 模板生成
const renderCard = (title, body) => `
<div class="card">
<h2>${title}</h2>
<p>${body}</p>
</div>
`
国际化(i18n)
function i18n(strings, ...values) {
const template = strings.join('%s')
const translated = lookupTranslation(template) // 翻译查找
return formatTranslated(translated, values)
}
const msg = i18n`Hello, ${name}, you have ${count} items`
SQL 查询构建(参数化)
// 标签模板可用于安全构建 SQL 参数
function sql(strings, ...values) {
return {
text: strings.join('?'),
values: values
}
}
const query = sql`SELECT * FROM users WHERE id = ${userId}`
// { text: 'SELECT * FROM users WHERE id = ?', values: [userId] }
CSS-in-JS
const Button = styled.button`
background: ${props => props.primary ? 'blue' : 'white'};
color: ${props => props.primary ? 'white' : 'black'};
`
边界与常见误解
- 误解:模板字符串会自动转义 HTML。 不会。
${}内的值不会被自动转义,仍需手动防御 XSS。 - 误解:反引号和单引号一样。 反引号是独立的语法结构,功能完全不同(支持插值和多行)。
- 误解:模板字符串性能差。 与字符串拼接性能差异可忽略,标签模板有额外开销但通常不在热路径。
- 边界:标签模板的第一个参数 数组长度始终比 values 多一个,因为它是”分割”关系。
- 边界:嵌套模板字符串 语法合法但可读性差,建议提取为变量。
- 边界:带换行的模板字符串 会保留所有空白和换行符,注意缩进。
最短记忆方式
- 反引号包裹,
${}插值,支持多行 - 标签模板 = 函数 + 模板字符串
- 不会自动转义,安全场景需额外处理