javascript对象转原始类型时,按hint("string"/"number"/"default")决定valueof与tostring调用顺序:hint为"string"时先tostring,"number"或非date的"default"时先valueof;任一方法返回原始值即成功,否则尝试另一方法,均失败则抛typeerror。

当 JavaScript 需要将一个对象转为原始类型(如字符串、数字)时,会按特定规则尝试调用 valueOf 和 toString 方法。执行顺序不是随意的,而是由抽象操作 [[ToPrimitive]] 定义的,且取决于期望的“原始类型目标”("default"、"string" 或 "number")。
转换目标决定方法调用优先级
JavaScript 在触发隐式转换(比如 + obj、'' + obj、String(obj)、Number(obj))时,会传入一个 hint(提示),告诉对象“我更希望你变成什么类型”:
-
hint = "string":优先调用
toString();若返回原始值,就用它;否则再调用valueOf() -
hint = "number":优先调用
valueOf();若返回原始值,就用它;否则再调用toString() -
hint = "default"(多数二元运算符,如
+、==):一般等同于"number",但 Date 对象例外(对 Date 使用"default"时优先toString)
必须返回原始值,否则报错
无论调用哪个方法,只要它存在且可调用,JS 就会检查其返回值:
- 如果返回的是原始类型(string / number / boolean / null / undefined / symbol / bigint),则转换成功,停止后续步骤
- 如果返回的是对象(包括数组、函数、另一个对象),则继续尝试另一个方法
- 如果两个方法都返回对象(或不存在/不可调用),就会抛出
TypeError: Cannot convert object to primitive value
实际例子看执行过程
定义一个自定义对象:
const obj = {valueOf() { console.log('valueOf called'); return {} },
toString() { console.log('toString called'); return 'hello' }
};
执行 String(obj)(hint = "string"):
- 先调
obj.toString()→ 返回'hello'(原始值)→ 转换完成,输出"hello"
执行 Number(obj)(hint = "number"):
- 先调
obj.valueOf()→ 返回空对象{}(非原始值)→ 继续 - 再调
obj.toString()→ 返回'hello'→ 被传给Number('hello')→ 得到NaN
执行 obj + ''(hint = "default",非 Date):
- 行为等价于 hint = "number" → 先
valueOf,再toString
自定义时的实用建议
- 若对象逻辑上更接近“数值含义”(如 Money、Point),优先让
valueOf返回合理数字 - 若对象主要用作标识或描述(如 User、Config),优先让
toString返回有意义字符串 - 避免两个方法都返回对象,否则任何强制转换都会失败
- 不手动删掉
toString或valueOf——继承自Object.prototype的默认实现可能干扰预期行为











