在构造函数原型上重写 tostring() 或 valueof() 方法可控制类型转换行为:tostring 优先用于字符串转换,valueof 优先用于数值转换,二者需返回原始值且协同工作以避免陷阱。

在构造函数原型上实现类型转换逻辑,核心是重写 toString() 或 valueOf() 方法,因为 JavaScript 在隐式或显式类型转换(如 Number(obj)、String(obj)、obj + ''、if (obj) 等)时,会按规则调用这两个方法获取原始值。
为什么原型上的方法影响类型转换
当对一个实例对象执行类型转换时:
-
Number(obj)先尝试调用obj.valueOf();若返回非原始值,再调用obj.toString();最后对得到的字符串按Number规则解析 -
String(obj)优先调用obj.toString();若返回非字符串原始值,则 fallback 到valueOf();若仍不满足,抛错 - 隐式转换(如
'' + obj或obj == 123)也遵循类似流程
在原型上定义 toString 实现字符串转换
这是最常用、最安全的方式。例如自定义一个表示金额的类:
function Money(amount) {
this.value = Number(amount) || 0;
}
Money.prototype.toString = function() {
return `¥${this.value.toFixed(2)}`;
};
const m = new Money(99.5);
console.log(String(m)); // "¥99.50"
console.log('Total: ' + m); // "Total: ¥99.50"
在原型上定义 valueOf 实现数字转换
若希望实例能自然参与算术运算,应实现 valueOf 返回数值:
- 确保返回的是原始类型(number/string/boolean),不能是对象
- 与
toString协作时注意优先级:Number()优先用valueOf,String()优先用toString
Money.prototype.valueOf = function() {
return this.value;
};
console.log(Number(m)); // 99.5
console.log(m + 10); // 109.5
console.log(m == 99.5); // true(隐式调用 valueOf)
避免常见陷阱
以下做法容易导致意外行为:
- 在
toString中返回非法数字字符串(如"NaN"或"123abc"),会导致Number(obj)得到NaN - 让
valueOf返回对象(如{x: 1}),会触发二次调用toString,可能陷入无限递归 - 未同时提供
toString和valueOf,导致某些上下文(如模板字符串或 JSON.stringify)出错 - 忽略
null/undefined的边界处理,在方法内部直接访问属性可能报错











