Menu

JavaScript 字符串与模板字面量:反引号、插值与常用方法

JavaScript 中字符串的用法:引号、反引号、插值、多行文本,以及你真正会用到的方法。

本页包含可运行的编辑器。编辑、运行,立即查看输出。

写字符串的三种方式

JavaScript 提供了三种字符串定界符。其中两种可以互换,第三种能做更多事。

单引号和双引号生成的字符串完全相同,选一种并坚持下去就好(大多数现代代码库默认用单引号,或者交给格式化工具决定)。反引号生成的是模板字面量,有趣的地方就在这里:它支持插值,还能跨越多行。

在底层,三种写法生成的都是同一种原始字符串类型。定界符只是语法上的选择。

转义序列与内嵌引号

在字符串中,反斜杠表示转义序列的开始。常见的有 \n(换行)、\t(制表符)、\\(反斜杠本身),以及用来嵌入与开头相同引号的 \" / \':

换用另一种引号,就能避免大部分转义:'She said "hi" and left.' 不需要任何反斜杠。务实比教条更重要。

模板字面量:反引号的超能力

模板字面量能做两件普通字符串做不到的事。第一,它可以用 ${...} 插入表达式:

${...} 里面的任何内容都是 JavaScript 表达式,而不只是变量名。算术运算、函数调用、三元表达式,甚至其他模板字面量,都可以:

第二,模板字面量可以跨越多行,无需 \n:

源代码中的换行会成为字符串中的换行。只要比一个简短的标签长,反引号几乎总是正确的选择。

插值胜过拼接

在模板字面量出现之前,构造动态字符串的唯一方法是 + 运算符:

两者的输出完全相同。模板字面量读起来就像它要构造的那句话,而 + 版本迫使你盯着引号、空格和拼接运算符。只有在往已有字符串末尾追加一小段内容时才用 +。更长的内容,就用反引号。

字符串是不可变的

每个看起来在修改字符串的方法,实际上都会返回一个新字符串:

如果你想要修改后的结果,就必须把它赋给某个变量。初学者常在这里栽跟头:写了 s.replace("a", "b"),以为 s 会改变。它不会。JavaScript 中的字符串和数字一样:值本身无法被修改,只能让变量指向一个新值。

你真正会用到的字符串方法

完整的字符串 API 很庞大。你每天会用到的就这几个:

几点值得记住:

  • length 是属性,不是方法,不加括号。
  • replace 配合普通字符串只替换第一个匹配。要替换所有匹配,用 replaceAll 或带 g 标志的正则表达式。
  • slice(start, end) 接收一个左闭右开的范围:end 位置的字符不包含在内。
  • slice 的负数索引从末尾开始算:s.slice(-3) 得到最后三个字符。

索引与遍历字符

字符串就像一个只读的字符数组。你可以按索引访问、可以遍历,但不能给某个位置赋值:

for...of 按码点遍历,能正确处理大多数 Unicode 字符。用索引(s[i])遍历的是 UTF-16 码元,可能会把 emoji 和其他非 BMP 字符劈成两半。普通文本两种方式都没问题;对于用户输入的内容,优先使用 for...of 或 [...s]。

标签模板字面量

还有一种形式值得了解,即使你不常自己写。标签模板字面量会调用一个函数,把静态的字符串片段和插值的值作为单独的参数传进去:

标签函数决定最终字符串的样子:它可以转义 HTML、安全地构造 SQL、编译 CSS,或者解析 GraphQL。你在库中(styled-components、graphql-tag、lit-html)看到这种写法的机会,远比自己写的机会多。但当你确实需要自定义字符串处理时,标签是最干净的工具。

常见陷阱

几个容易踩的坑:

  • 忘了把方法的结果赋值。 单独写 s.trim() 什么也不会改变。
  • 用 + 拼接数字和字符串。 "Age: " + 30 + 5 的结果是 "Age: 305",而不是 "Age: 35"。模板字面量能避开这个问题:`Age: ${30 + 5}`。
  • 混淆 == 和字符串比较。 后面会专门讲相等性,但 "1" == 1 是 true,而 "1" === 1 是 false。优先使用 ===。
  • 以为 length 等于字符个数。 对于 emoji 和其他代理对字符,"🙂".length 是 2,而不是 1。需要用户感知的字符数时,用 [..."🙂"].length 或 Array.from(s).length。

下一篇:数字与 BigInt

字符串是一种原始类型,数字是另一种,而 JavaScript 的数字系统有它自己的怪癖:整数和浮点数共用一个 Number 类型,不够用时还有 BigInt。这就是下一页的内容。

常见问题

JavaScript 中引号和反引号有什么区别?

单引号(')和双引号(")创建的都是普通字符串,两者可以互换。反引号(`)创建的是模板字面量,支持用 ${...} 插值,还能跨越多行而无需转义字符。只要你要插入变量或写多行文本,就用反引号。

JavaScript 中怎样把变量插入字符串?

使用模板字面量:用反引号包住字符串,把表达式放进 ${...} 中。例如 `Hello, ${name}!` 会计算 name,再把结果拼接进去。里面可以放任何表达式:${a + b}、${user.name.toUpperCase()},甚至嵌套的模板字面量。

JavaScript 的字符串是不可变的吗?

是的。每个字符串方法(toUpperCase、slice、replace 等)都会返回一个新字符串,而不是修改原字符串。如果你写了 s.toUpperCase() 却没把结果赋给任何变量,什么都不会改变。这和 Python 或 Java 中字符串的模型一样。

什么是标签模板字面量?

标签模板字面量会调用一个函数,把模板中的字符串片段和插值的值作为单独的参数传进去:tag`Hello, ${name}` 会调用 tag(["Hello, ", ""], name)。styled-components 和 graphql-tag 等库就是用标签在生成最终值之前解析或转换模板的。

Coddy 编程语言插图

和 Coddy 一起学编程

开始