valueof() 和 tostring() 在原始类型转换中按 toprimitive 的 hint 优先级调用:hint 为 "number" 时先 valueof() 后 tostring(),"string" 时相反,"default" 多数按 "number" 处理(date 例外);二者均须返回原始值,否则回退或报错。

valueOf() 和 toString() 在原始类型强制转换中不是“并列选项”,而是有明确优先级和分工的——引擎按规范顺序尝试,不是看谁“权重高”,而是看当前转换目标需要什么类型的原始值。
转换目标决定谁先被调用
JavaScript 的 toPrimitive 抽象操作会根据期望的类型提示(hint)决定首选方法:
- hint 是 "number"(如
+obj、obj == 5、Number(obj))→ 先调 valueOf();若返回非原始值(比如仍是个对象),再 fallback 到 toString() - hint 是 "string"(如
"" + obj、String(obj)、alert(obj))→ 先调 toString();若返回非字符串,再试 valueOf() - hint 是 "default"(如
obj == "123"或无上下文的obj + "")→ 多数引擎(V8等)默认按 "number" 处理,即先 valueOf;但 Date 对象例外,它对 default hint 优先用 toString
返回值类型必须匹配,否则会被忽略
两个方法都必须返回原始值(string / number / boolean / symbol / null / undefined),否则该次调用视为“失败”:
-
valueOf()返回一个对象(比如{}或数组)→ 引擎直接跳过,继续尝试toString() -
toString()返回数字123(不是字符串)→ 不算有效字符串结果,也会触发回退(如果还有机会) - 两者都返回对象 → 抛出
TypeError: Cannot convert object to primitive value
常见对象的默认行为差异
不同内置对象对这两个方法的实现不同,直接影响转换结果:
-
Date:重写了
valueOf()返回时间戳(number),toString()返回可读日期字符串。所以+new Date()得数字,"" + new Date()得字符串 -
Array:
toString()被重写为.join(","),所以[1,2] + ""→"1,2";而valueOf()没重写,返回数组本身(对象),不参与数值运算 -
Object(原生):两者都返回对象自身或
"[object Object]",因此纯对象在数学运算中通常转成NaN(因为valueOf()→ 对象 → 忽略 →toString()→ 字符串 →NaN)
重写时的关键约束
自定义类中重写这两个方法,不能只考虑“想输出什么”,更要匹配调用场景的语义:
- 若希望对象能参与加减乘除,
valueOf()应返回有意义的 number(如货币类返回金额数值) - 若希望
console.log(obj)显示友好格式,toString()应返回清晰字符串(如"User{id: 123, name: 'Alice'}") - 避免
toString()返回数字、valueOf()返回字符串——这会让引擎困惑,可能绕过预期路径










