Symbol.toPrimitive是对象隐式转原始值的唯一入口,优先级高于toString和valueOf;触发场景包括模板字符串(hint="string")、算术运算(hint="number")、+obj(hint="number")、==/>,<等比较(hint="default"),且必须按hint返回对应原始类型,否则报错。

Symbol.toPrimitive 是 JavaScript 中控制对象隐式转原始值的“最高裁决者”。只要它存在且可调用,引擎就跳过 toString 和 valueOf,直接执行它——不是“之一”,而是“唯一入口”。
哪些操作会触发它?
所有需要把对象变成 string/number 的隐式场景,都会走 ToPrimitive 抽象操作,并带上 hint 参数:
- 模板字符串:`${obj}` → hint = "string"
- 算术运算(除 + 拼接外):-obj、obj * 2、obj / 10 → hint = "number"
- 一元加号:+obj → hint = "number"
- 比较运算符(非严格相等):obj == 42、obj > 10 → hint = "default"(但 Date 例外,它对 default 会走 string)
- 二元加号(+):obj + 1 先对 obj 调用 ToPrimitive(hint="default");若结果是字符串,则整体拼接;否则转数字相加
为什么说它“优先级最高”?
规范中 ToPrimitive 的执行流程是线性的、有明确顺序的:
- 第一步:检查对象是否有 [[Get]](Symbol.toPrimitive) 且该属性是可调用函数 → 有则立即调用,不看其他方法
- 第二步:若无 Symbol.toPrimitive,才按 hint 分支尝试 valueOf() 或 toString()
- 也就是说,哪怕 toString 返回 "123"、valueOf 返回 42,只要 Symbol.toPrimitive 存在,它们在隐式转换里就完全失效
hint 参数不是摆设,必须认真处理
hint 不是提示,而是上下文强约束。你不能忽略它的值,也不能返回错误类型:
- hint === "string" 时,应返回 string(如 `"User(id:5)"`),返回 number 会被自动转成字符串,但语义错位
- hint === "number" 时,应返回 number;若计算逻辑可能出 NaN(比如 `parseInt(this.id)` 失败),需兜底,否则报 TypeError
- hint === "default" 通常出现在 == 或 + 场景,**引擎不会帮你 fallback** —— 你得自己决定返回 string 还是 number。多数情况下选 number 更符合直觉(如 `obj == 100` 希望比数值)
常见陷阱与兼容性注意
它虽强大,但容易踩坑:
- 返回非原始值(如 `{}`、`[]`、`new Date()`)→ 直接抛 TypeError: Cannot convert object to primitive value
- 某些调试工具(旧版 Chrome 控制台、部分 IDE 预览)仍绕过 Symbol.toPrimitive,直接调用 toString() → 显示内容和 console.log(obj) 不一致
- toString/valueOf 依然可以手动调用,但它们在隐式转换中彻底失权;老代码若依赖 valueOf 行为,加了 Symbol.toPrimitive 后可能逻辑突变

















