JavaScript 中的"字符串"其实分为两种体系:
- 普通字符串(String Literal)
- 模板字面量(Template Literal)
它们在执行能力、格式保留、函数行为上完全不同。
一、两种字符串的本质区别
1️⃣ 普通字符串
ini
const str = "hello world";
特点:
- 纯文本
- 不执行表达式
- 不保留结构(换行需要
\n)
2️⃣ 模板字面量
ini
const str = `hello world`;
特点:
- 支持
${} - 支持多行
- 保留空格与换行
- 可以被"标签函数"处理
二、重点1:模板字符串会保留空格和换行(非常关键)
这是模板字符串最容易忽略的行为之一。
示例:换行会原样保留
ini
const str = `hello
world`;
console.log(str);
输出:
hello
world
示例:空格也会保留
ini
const str = ` hello `;
console.log(str);
输出:
hello
👉 核心结论
模板字符串是"所见即所得"的文本结构
三、重点2:`` 可以作为函数参数(标签函数机制)
这是模板字面量非常核心的能力:
模板字符串可以"变成函数调用参数"
示例:
javascript
function tag(strings, ...values) {
console.log(strings);
console.log(values);
}
tag`hello ${1} world ${2}`;
实际发生的是:
css
tag(["hello ", " world ", ""], 1, 2);
👉 本质
不是模板字符串"执行函数",而是:
模板字符串被"重写成函数调用"
🔥 等价关系:
ini
tag`a=${1}`
等价于:
css
tag(["a=", ""], 1);
👉 结论
`` 不是字符串,而是"函数调用语法糖入口"
四、重点3:${} 只是表达式执行,不是拼接
javascript
`result: ${fn()}`
发生的是:
- 执行 fn()
- 获取返回值
- 转字符串
- 插入模板
示例
javascript
function fn() {
return "OK";
}
console.log(`value: ${fn()}`);
输出:
makefile
value: OK
👉 关键点
${}是 JS 表达式执行区域
五、重点4:Promise 不会自动展开
javascript
const p = Promise.resolve("data");
console.log(`value: ${p}`);
输出:
typescript
value: [object Promise]
原因
模板字符串不会:
- await
- then
- 解析异步
它只做:
隐式类型转换(ToString)
结论
Promise 在模板字符串中只是普通对象
六、重点5:对象会自动触发 toString / valueOf
javascript
const obj = {
toString() {
return "HELLO";
}
};
console.log(`${obj}`);
输出:
HELLO
本质
触发的是:
JavaScript 隐式类型转换(ToPrimitive)
顺序:
- valueOf
- toString
七、重点6:String.raw ------ 原始字符串
普通字符串
swift
"test \n test"
输出:
bash
test
test
String.raw
bash
String.raw`test \n test`
输出:
bash
test \n test
👉 本质
String.raw = 禁止转义解析
八、重点7:for...of 遍历字符串
arduino
for (const c of "abc") {
console.log(c);
}
输出:
css
a
b
c
本质
字符串实现了:
iterable(可迭代协议)
等价于:
scss
str[Symbol.iterator]()
👉 特点
- 按字符遍历
- 不依赖 String 对象包装
- 不受 raw 影响
九、核心统一理解(最重要)
当你写:
javascript
`${obj}`
JS 实际做的是:
obj
↓
ToPrimitive
↓
valueOf → toString
↓
得到字符串
↓
插入模板
十、最终总结(重点版)
1️⃣ `` 不是普通字符串,而是"模板执行结构"
2️⃣ 模板字符串可以作为函数参数(tagged template)
3️⃣ ${} 是表达式执行区,不是拼接
4️⃣ 模板字符串会保留空格和换行(非常关键)
5️⃣ Promise 不会自动展开(不会 await)
6️⃣ 对象会触发 ToPrimitive(valueOf / toString)
7️⃣ String.raw 只是关闭转义解析
8️⃣ for...of 基于 iterator,不依赖 String 包装对象
十一、一句话终极理解
JavaScript 模板字面量本质是"表达式求值 + 隐式类型转换 + 格式保留 + 可标签化的字符串结构",而不是字符串拼接语法。
本文部分内容借助 AI 辅助生成,并由作者整理审核。