前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
首页程序员面试题库模板字符串 类型转换 表达式
JavaScript值与类型

模板字符串和加号拼接,类型转换有什么不一样?嵌套时要注意什么?

模板字符串的 ${} 直接把值转成字符串,对象会优先调用 toString;+ 拼接先做默认的原始值转换,对象会优先调用 valueOf。普通值两种写法结果一样,对象同时定义了 valueOf 和 toString 时就会出现差别。

前端进阶之旅 · 一题精讲更新于 2026.09.29
JavaScript#值与类型
先看核心答案读代码示例
理解线索

两种拼接的转换路径

  1. 模板字符串对插值结果直接做字符串转换,对象按 toString 优先的顺序取原始值
  2. + 拼接先把两边转成原始值,对象按 valueOf 优先,有一边是字符串才拼接
  3. 插值表达式${} 里是完整的表达式,先算出结果,再转成字符串

Date 对象是例外,它在 + 里也会先调 toString,所以 '' + date 和模板字符串的结果一样。真正会不一样的是自己同时写了 valueOf 和 toString 的对象。

核心回答

先记住这个答案

对数字、布尔、null、undefined、数组这些值,模板字符串和 + 拼接的结果完全一样。区别出在对象上:模板字符串的 ${} 对插值结果做的是「转成字符串」,对象会先调用 toString;+ 做的是「默认转换」,对象会先调用 valueOf,拿到原始值后如果有一边是字符串才拼接。所以一个同时定义了 valueOf 和 toString 的对象,两种写法会输出不同的内容。另外 Symbol 不能隐式转字符串,放进 ${} 或 + 都会抛 TypeError。

  • ${} 按字符串转换,对象先调 toString
  • + 按默认转换,对象先调 valueOf
  • Symbol 不能隐式插入模板字符串
  • 插值里可以嵌套模板字符串,反引号不会互相截断

同一个对象,两种拼接

用一个同时定义了 valueOf 和 toString 的对象来对比,差别最明显。

对照转换结果JavaScript
const price = {
  valueOf() { return 99 },
  toString() { return '九十九元' }
}
// + 按默认 hint 转换,先调 valueOf;模板字符串按 string hint,先调 toString
console.log('价格:' + price)
console.log(`价格:${price}`)
// 其它值两种写法结果一样
console.log(`${null} ${undefined} ${[1, [2, 3]]} ${{}}`)
// 嵌套:插值里可以再写模板字符串,外层不会被里层的反引号截断
const items = ['a', 'b']
console.log(`共 ${items.length} 项:${items.map((x) => `<li>${x}</li>`).join('')}`)
// 插值里的运算先算完再转字符串
console.log(`${1 + 2}${'3'}`, `${'1' + 2 + 3}`)
查看输出与解释
价格:99
价格:九十九元
null undefined 1,2,3 [object Object]
共 2 项:<li>a</li><li>b</li>
33 123

前两行的差别在转换提示。+ 拿到对象时会以 default 为提示转原始值,普通对象在这种提示下先试 valueOf,得到 99。模板字符串以 string 为提示,先试 toString,得到「九十九元」。hint 可以理解成「调用方希望拿到什么类型」,引擎据此决定先调哪个方法。 第三行说明普通值没有区别:null 和 undefined 变成同名字符串,数组会被扁平地用逗号连接,空对象变成 [object Object]。 最后一行要注意 ${} 里是完整的表达式。${1 + 2} 先算出数字 3 再转字符串;${'1' + 2 + 3} 从左往右算,'1' + 2 已经是字符串,结果是 '123'。

嵌套和标签模板

插值里再写模板字符串是合法的,解析器会按 ${ 和 } 配对,里层的反引号不会提前结束外层字符串。拼 HTML 列表、按条件拼类名时很常用,上面代码里 items.map 那一行就是例子。嵌套超过两层就很难读了,这时应该把里层抽成变量或函数。

另一个容易忽略的点是,模板字符串前面加一个函数名就变成了标签模板,写法是函数名后面紧跟反引号,中间没有括号。这时插值不会被转成字符串,而是原样作为参数传给这个标签函数,第一个参数是字符串片段数组。styled-components、String.raw 都是靠这个机制工作的,所以在标签模板里放对象、函数都不会触发 toString。

回答前,多想一步

容易答错的地方

模板字符串就是 + 拼接的语法糖
结果大多数时候一样,但转换路径不同。对象同时有 valueOf 和 toString 时,两者会得到不同的字符串,面试官问的就是这个差别。
${} 里放对象会自动转成 JSON
不会。普通对象会变成 [object Object],要看内容得自己写 JSON.stringify(obj)。数组会调用 join,所以 ${[1, [2, 3]]} 得到的是 1,2,3,嵌套结构也被抹平了。
普通引号字符串里也能写 ${}
只有反引号才会解析插值。单引号或双引号里的 ${name} 就是普通文本,原样输出,这是从别的地方复制代码时常见的 bug。
试着用自己的话回答

面试官还会怎么问?

Symbol 放进模板字符串会怎样?怎么安全打印?

直接抛 TypeError: Cannot convert a Symbol value to a string。要显式转换:${String(sym)} 或 ${sym.description}。String() 对 Symbol 是特殊处理过的,只有隐式转换会报错。

BigInt 在模板字符串和 + 里表现一样吗?

模板字符串里 ${10n} 得到 '10',和 '' + 10n 一样,因为有一边是字符串时 BigInt 会正常转字符串。但 10n + 1 会抛 TypeError,BigInt 和普通数字不能直接做算术运算。

模板字符串里的换行和缩进会保留吗?

会原样保留,包括源代码里的缩进空格。写多行 SQL 或 HTML 时,每行前面的缩进都会进到字符串里。不想要时可以把内容顶格写,或者拼好后用 trim 和正则去掉多余空白。

从一道题,走向一组知识

把知识连起来

值与类型

JSON.stringify 遇到 undefined、函数和 Symbol 会怎么处理?

想把对象完整地放进字符串,模板字符串只会得到 [object Object],这时要用 JSON.stringify。

值与类型

Symbol.toPrimitive 是怎么让对象自己决定转成数字还是字符串的?

模板字符串用的是 string hint,+ 用的是 default hint,Symbol.toPrimitive 能同时拿到这两种 hint。

参考资料

  • JavaScript:值与类型参考资料

示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。

本题目录
  1. 先记住这个答案
  2. 同一个对象,两种拼接
  3. 嵌套和标签模板
  4. 容易答错的地方
  5. 面试官还会怎么问
  6. 把知识连起来
读懂,再试着讲出来

先看核心答案,再读代码。最后展开追问,检查自己有没有遗漏边界。

试着回答追问
浏览全部面试题理解原理,也关注真实的使用场景。回到顶部 ↑