JavaScript中重写Number原型valueOf()遇栈溢出,如何正确实现?
问题分析与解决方案
栈溢出错误原因
你遇到的RangeError: Maximum call stack size exceeded是因为无限递归调用:
- 当执行
new Number(33).toString()时,代码里的"This is the number: " + this会触发JS的类型转换规则:要把this(Number包装对象)转成原始值,JS会优先调用valueOf方法。 - 但你重写的
valueOf直接返回了this(Number对象本身,不是原始数值),JS发现拿到的还是对象,就会继续尝试调用toString来转成原始值。 - 而
toString里又有+ this,再次触发类型转换→调用valueOf→返回对象→调用toString,无限循环直到栈溢出。
另外,移除console.log(new Number(33).toString());后代码能运行,是因为此时只调用valueOf返回Number对象,部分环境的console.log会直接展示对象结构,不会强制触发完整的字符串转换,因此没触发递归。
重写valueOf返回目标字符串的正确方式
首先要明确:valueOf的设计初衷是返回对象对应的原始值,强行让它返回字符串不符合标准行为,但如果业务需要这么做,核心是要避免递归调用——必须先拿到Number包装对象对应的原始数值,而不是直接用this触发类型转换。
修改后的代码:
// 重写toString,避免触发无限递归 Number.prototype.toString = function () { // 调用原生Number的valueOf获取原始数值 const rawNum = Object.getPrototypeOf(this).valueOf.call(this); return "This is the number: " + rawNum; }; Number.prototype.valueOf = function () { // 先拿到原始数值,再拼接目标字符串 const rawNum = Object.getPrototypeOf(this).valueOf.call(this); return `The number is ${rawNum}`; }; console.log(new Number(33).toString()); // 输出:This is the number: 33 console.log(new Number(34).valueOf()); // 输出:The number is 34
核心要点
Object.getPrototypeOf(this).valueOf.call(this):绕开我们重写的方法,调用Number原生原型上的valueOf,直接获取包装对象对应的原始数值,彻底打破递归链。- 绝对不能直接用
this拼接字符串,否则会反复触发类型转换,再次陷入无限递归。
内容的提问来源于stack exchange,提问作者yarslvd
相关产品推荐
相关产品推荐

