字符串是JavaScript中使用频率最高的数据类型之一,无论是拼接HTML片段、组装请求参数,还是格式化日志输出,都离不开字符串操作。在ES5时代,开发者只能依靠加号拼接和转义符来处理复杂字符串,一旦遇到多行文本或嵌套引号,代码可读性就会直线下降。ES6引入的模板字面量(Template Literals)从根本上改变了这一局面。本文将带你回顾ES5的字符串处理方式,再深入剖析ES6模板字面量的语法细节与底层机制。

一、ES5时代的字符串处理:拼接与转义的困境
在ES5及更早的版本中,JavaScript的字符串只有单引号和双引号两种写法,两者在功能上完全等价,选择哪种更多是团队风格约定。当需要在字符串中嵌入变量时,唯一的方式就是使用加号拼接:
var name = '张三'; var age = 25; var msg = '用户' + name + '今年' + age + '岁了'; console.log(msg); // 用户张三今年25岁了
这种写法在变量少的时候还算清晰,但一旦变量数量增多,加号、引号交错出现,代码就会变得难以维护。更麻烦的是漏写加号导致的隐式类型转换问题,比如var msg = '年龄:' age;这样的写法会直接抛出语法错误,而如果把数字和字符串混拼,还可能出现意料之外的结果。
另一个明显的痛点是多行字符串。ES5的字符串不支持直接换行,想在字符串里写多行文本,只能用\n转义符或者在每行末尾加反斜杠:
// 方式一:使用\n转义 var html = '<div class="box">\n <p>标题</p>\n</div>'; // 方式二:行尾反斜杠(续行符) var text = '第一行\ 第二行';
方式一的可读性极差,HTML结构完全靠脑补;方式二虽然看起来换行了,但续行符后面必须紧跟换行符,任何多余的空格都会导致语法错误,而且输出的字符串其实并不包含真正的换行符。此外,引号嵌套也是常见坑:字符串本身用单引号包裹时,内部的单引号必须写成\',稍不注意就会导致字符串提前截断。
二、ES6模板字面量的基本语法与表达式插值
ES6用一对反引号``定义了模板字面量,它解决了上述所有痛点。最基本的用法是变量插值,语法是在${}中放置任意表达式:
const name = '张三';
const age = 25;
const msg = `用户${name}今年${age}岁了`;
console.log(msg); // 用户张三今年25岁了注意${}中放置的不只是变量,而是完整的JavaScript表达式,可以调用函数、执行运算、访问对象属性,甚至嵌套另一个模板字面量:
const price = 99.5;
const count = 3;
const output = `总价:${(price * count).toFixed(2)}元,省略小数:${Math.round(price)}`;
// 嵌套模板字面量
const items = ['苹果', '香蕉'];
const list = `购物清单:${items.map(i => `【${i}】`).join(' ')}`;
console.log(list); // 购物清单:【苹果】 【香蕉】多行字符串的支持则更加直观。反引号内的换行和空格会被原样保留,不需要任何转义符:
const html = `<div class="box"> <p>标题</p> <p>内容区域</p> </div>`;
需要提醒的是,正因为换行被原样保留,代码缩进也会进入字符串本身。如果对字符串内容有严格要求(比如生成配置文件),建议不要在反引号内随意缩进,或者用后续介绍的标签模板做处理。
引号嵌套问题也顺带解决了:模板字面量内部可以随意使用单引号和双引号,不需要转义。唯一的例外是反引号本身和${序列,它们需要用\转义,例如\`和\${。ES2018还引入了模板字面量修订版,允许在带标签的模板中使用不合法的转义序列,进一步放宽了限制。
三、标签模板:模板字面量的高级用法
模板字面量还有一种进阶形态叫标签模板(Tagged Templates)。它在反引号前面加上一个函数名,这个函数会被调用来处理模板字符串。函数的第一个参数是静态字符串数组,其余参数依次对应各个插值表达式的结果:
function tag(strings, ...values) {
console.log(strings); // ['你好,', ',欢迎来到', '']
console.log(values); // ['张三', '前端世界']
return strings[0] + values[0].toUpperCase() + strings[1] + values[1];
}
const user = '张三';
const result = tag`你好,${user},欢迎来到${'前端世界'}`;
console.log(result); // 你,张三,欢迎来到前端世界(此处为演示拼接逻辑)这里用到了rest参数...values收集所有插值。静态字符串数组上还有一个raw属性,保存的是未经转义处理的原始字符串,比如strings.raw[0]会保留\n的字面形式而非换行符。
标签模板最经典的应用场景是防注入处理。在拼接SQL或HTML时,直接插值用户输入会带来注入风险,我们可以编写一个标签函数对动态内容统一转义:
function safeHtml(strings, ...values) {
let result = '';
strings.forEach((str, i) => {
result += str;
if (i < values.length) {
result += String(values[i])
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>');
}
});
return result;
}
const userInput = '<script>alert(1)</script>';
const page = safeHtml`<div>${userInput}</div>`;
console.log(page); // <div><script>alert(1)</script></div>一些国际化库也借助标签模板实现多语言模板匹配,前端框架中的CSS-in-JS方案(如styled-components)同样基于这一机制。
四、新旧方案对比与选择建议
模板字面量并非只是语法糖,它在可读性、可维护性和功能扩展性上全面超越ES5的拼接方式。下面对比两者的核心差异:
| 特性 | ES5字符串拼接 | ES6模板字面量 |
|---|---|---|
| 变量嵌入 | 加号拼接,易出错 | ${}插值,直观清晰 |
| 多行文本 | \n或续行符,可读性差 | 原生支持换行 |
| 引号嵌套 | 需要转义 | 无需转义 |
| 表达式支持 | 需拆出变量再拼接 | ${}内可写任意表达式 |
| 扩展能力 | 无 | 标签模板、raw属性 |
在浏览器兼容性方面,主流浏览器早已全面支持模板字面量,除非需要兼容非常老旧的环境(如IE11),否则没有理由继续使用加号拼接。如果项目必须兼容旧环境,也可以借助Babel等构建工具将模板字面量编译回ES5语法。
使用时还有几个细节值得注意:第一,${后面必须紧跟}闭合,表达式内部的}需要正确配对,比如对象字面量要写成${({name: '张三'}).name}的形式避免歧义;第二,插值结果会被隐式转换为字符串,null和undefined会输出对应的字面文字,Array会调用join(',') 的逻辑;第三,模板字面量每次求值都会生成新字符串,JavaScript的字符串不可变,频繁大量拼接时性能差异主要来自引擎优化,日常业务无需过度担心。
总的来说,模板字面量让JavaScript的字符串处理从繁琐走向优雅。掌握它的基础语法只是第一步,理解标签模板的执行机制,才能在实际项目中发挥出这套语法的真正威力。建议在阅读完本文后动手实现一个自己的标签函数,比如时间格式化或金额格式化工具,实践会帮助你更牢固地掌握这些知识。
JavaScript字符串处理模板字面量ES6修改时间:2026-09-07 22:20:40