模板字符串是 ES6(ECMAScript 2015)引入的重要特性,它解决了 JavaScript 中字符串拼接的痛点问题。在 ES6 之前,开发者需要使用字符串连接符(+)来构建复杂字符串,这种方式不仅繁琐且易出错,尤其在处理多行文本和变量插值时。模板字符串使用反引号(`)代替单引号或双引号,提供了更优雅、可读性更强的字符串处理方式。
// 基本用法
const name = 'John'
const greeting = `Hello, ${name}!`
console.log(greeting) // "Hello, John!"
// 表达式计算
const a = 10
const b = 20
console.log(`Sum: ${a + b}`) // "Sum: 30"
// 调用函数
function getTime() {
return new Date().toLocaleTimeString()
}
console.log(`Current time: ${getTime()}`)
// 传统写法
const multiLine = 'line 1\n' + 'line 2\n' + 'line 3'
// 模板字符串写法
const multiLine = `
line 1
line 2
line 3
`
// HTML模板
const html = `
${title}
${content}
`
function tag(strings, ...values) {
console.log(strings) // 字符串数组
console.log(values) // 插值数组
return '处理结果'
}
const name = 'John'
const age = 30
const result = tag`Name: ${name}, Age: ${age}`
// 安全的HTML模板
function safeHtml(strings, ...values) {
const escaped = values.map(value =>
String(value).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>')
)
return strings.reduce((result, str, i) => result + str + (escaped[i] || ''), '')
}
const userInput = ''
const safe = safeHtml`${userInput}`
// styled-components风格
function styled(strings, ...values) {
return function (props) {
const result = strings.reduce((acc, str, i) => {
const value = values[i]
const resolved = typeof value === 'function' ? value(props) : value
return acc + str + (resolved || '')
}, '')
return result
}
}
const Button = styled`
background: ${props => (props.primary ? 'blue' : 'white')};
color: ${props => (props.primary ? 'white' : 'black')};
padding: 10px 20px;
border: none;
border-radius: 4px;
`
// URL构建
const baseUrl = 'https://api.example.com'
const endpoint = 'users'
const id = 123
const url = `${baseUrl}/${endpoint}/${id}`
// 动态类名
const className = `header ${isActive ? 'active' : ''} ${isHidden ? 'hidden' : ''}`
const table = 'users'
const fields = ['name', 'age']
const condition = 'age > 18'
const query = `
SELECT ${fields.join(', ')}
FROM ${table}
WHERE ${condition}
`
const i18n = {
greeting: (name, time) => `Hello ${name}, good ${time}!`,
farewell: name => `Goodbye ${name}, see you next time!`,
}
console.log(i18n.greeting('John', 'morning'))
使用场景
注意事项
性能考虑
join()
方法高效参考答案:
+
进行拼接\n
转义符${}
中放置任何有效的 JavaScript 表达式参考答案:
标签模板是模板字符串的高级用法,本质上是一个函数调用,函数名(标签)位于模板字符串之前。
格式:tag
`template string`
主要用途:
标签函数接收被模板字符串分割的文本数组作为第一个参数,后续参数为模板中的表达式值。
参考答案:
在模板字符串中,反引号(`)和美元符号加大括号(${)需要转义:
// 转义反引号
console.log(`这是一个转义的反引号:\``)
// 转义${}
console.log(`实际价格:\${price}美元`)
也可以使用标签模板函数来处理特殊字符:
function escape(strings, ...values) {
return strings.reduce((result, str, i) => {
let val = values[i] || ''
// 处理特殊字符
val = String(val).replace(/</g, '<').replace(/>/g, '>')
return result + str + val
}, '')
}
const html = escape`${userInput}`
参考答案:
模板字符串的 ${}
中可以包含任何有效的 JavaScript 表达式:
const name = 'World';
`Hello ${name}``\
2 + 2 = ${2 + 2}``\
Current time: ${new Date().toLocaleTimeString()}``\
${age > 18 ? ‘成年’ : ‘未成年’}``\
Welcome ${user.name}!``\
Uppercase: ${name.toUpperCase()}``\
Items: ${items.join(', ')}``表达式会被求值,然后转换为字符串并插入到结果字符串中。
参考答案:
模板字符串天然支持多行文本,只需直接在代码中换行即可:
const multiLine = `
这是第一行
这是第二行
这是第三行
`
需要注意的是:
function trimIndent(strings, ...values) {
const result = strings.reduce((acc, str, i) => acc + str + (values[i] || ''), '')
return result.replace(/^\s+/gm, '').trim()
}
const html = trimIndent`
多行文本,缩进会被移除
`
参考答案:
模板字符串的性能特点:
Array.join()
可能比模板字符串更高效实际开发中,应根据场景选择合适的方法:
join()
或 +=
等方式参考答案:
使用模板字符串实现国际化主要有两种方式:
1. 结合翻译对象:
const i18n = {
'zh-CN': {
greeting: name => `你好,${name}!`,
farewell: name => `再见,${name}!`,
},
'en-US': {
greeting: name => `Hello, ${name}!`,
farewell: name => `Goodbye, ${name}!`,
},
}
const userLang = 'zh-CN'
console.log(i18n[userLang].greeting('张三'))
2. 使用标签模板:
function i18n(strings, ...values) {
const locale = getCurrentLocale() // 获取当前语言环境
const translations = {
'zh-CN': ['欢迎', '您已登录', '天'],
'en-US': ['Welcome', 'You have been logged in for', 'days'],
}
const translated = translations[locale] || translations['en-US']
return strings.reduce((result, str, i) => {
return result + translated[i] + (values[i] !== undefined ? values[i] : '')
}, '')
}
const username = '张三'
const days = 5
const message = i18n`${username}! ${days}`
这种方法结合专业的 i18n 库(如 i18next)使用效果更佳。
参考答案:
相同点:
不同点:
${}
插值,JSX 使用{}
插值两者可以结合使用,如在 JSX 中使用模板字符串处理文本。
参考答案:
模板字符串可以嵌套,有以下几种方式:
1. 直接嵌套:
const name = 'World'
const greeting = `Hello ${`${name.toUpperCase()}`}!`
console.log(greeting) // "Hello WORLD!"
2. 使用函数返回模板字符串:
function emphasize(text) {
return `**${text}**`
}
const name = 'World'
const greeting = `Hello ${emphasize(name)}!`
console.log(greeting) // "Hello **World**!"
3. 条件嵌套:
const isAdmin = true
const username = 'Alice'
const greeting = `Welcome ${isAdmin ? `Admin ${username}` : username}!`
嵌套模板字符串在构建复杂模板时非常有用,但过度嵌套会降低可读性,应适度使用。
参考答案:
标签模板函数接收以下参数:
1. 第一个参数 (strings):
raw
属性,包含未处理的原始字符串2. 后续参数:
示例:
function tag(strings, ...values) {
console.log(strings) // ["Hello, ", "! You are ", " years old."]
console.log(strings.raw) // 同上,但转义字符不被处理
console.log(values) // ["John", 30]
return strings.reduce((result, str, i) => {
return result + str + (values[i] || '')
}, '')
}
const name = 'John'
const age = 30
const result = tag`Hello, ${name}! You are ${age} years old.`
处理这些参数的常见模式:
标签函数强大之处在于它可以完全控制模板的处理逻辑,不仅限于生成字符串。