模板字符串

ES6 用反引号表示的字符串语法,支持插值、多行和标签模板。

#type / concept #status / growing #resource / javascript #resource / ecmascript

[!info] related notes

模板字符串

一句话定义

模板字符串(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, '&amp;').replace(/</g, '&lt;')
      : ''
    return result + str + val
  }, '')
}

const userInput = '<script>alert("xss")</script>'
const safe = safeHTML`User said: ${userInput}`
// "User said: &lt;script>alert("xss")&lt;/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 多一个,因为它是”分割”关系。
  • 边界:嵌套模板字符串 语法合法但可读性差,建议提取为变量。
  • 边界:带换行的模板字符串 会保留所有空白和换行符,注意缩进。

最短记忆方式

  • 反引号包裹,${} 插值,支持多行
  • 标签模板 = 函数 + 模板字符串
  • 不会自动转义,安全场景需额外处理
创建于 2026/4/7 更新于 2026/5/27