在 javascript 中,valueof 和 tostring 的调用顺序取决于具体的运算场景:当进行字符串拼接或需要显示文本时,优先调用 tostring;当进行数值计算或布尔值转换时,优先调用 valueof。具体做法是理解引擎内部的 toprimitive 抽象操作,它会根据 hint(提示)参数决定尝试获取原始值的顺序。若未指定 hint 或为 default,对象类型通常先试 valueof 再试 tostring,而 date 对象则相反。

何时优先调用 toString
当运算涉及字符串上下文时,例如使用 + 运算符进行拼接,或者调用 console.log、alert 等输出方法时,JavaScript 引擎会优先调用 toString 方法将对象转换为字符串表示。如果 toString 返回的不是原始值,引擎才会回退到 valueOf。这种机制确保了对象在显示时能呈现人类可读的格式。

function MyString() {
this.val = "hello";
}
MyString.prototype.toString = function() {
console.log("Called toString");
return this.val;
};
MyString.prototype.valueOf = function() {
console.log("Called valueOf");
return 123;
};
var obj = new MyString();
console.log(obj + " world"); // 优先调用 toString
上述代码中,obj + " world" 触发了字符串拼接,因此 toString 被首先调用并返回 "hello",最终输出 "hello world"。如果注释掉 toString,引擎则会调用 valueOf 返回的数字 123 进行拼接,输出 "123 world"。
立即学习“Java免费学习笔记(深入)”;
何时优先调用 valueOf
当运算涉及数值比较、算术运算(如减法、乘法)或逻辑判断时,JavaScript 引擎会优先调用 valueOf 方法以获取对象的原始数值或布尔值。这是因为这些操作通常需要原始数据类型来进行计算。同样地,如果 valueOf 返回的不是原始值,引擎才会去调用 toString。这种策略优化了数学运算的效率,避免了不必要的字符串转换。

function MyNumber() {
this.val = 456;
}
MyNumber.prototype.toString = function() {
console.log("Called toString");
return "456";
};
MyNumber.prototype.valueOf = function() {
console.log("Called valueOf");
return 789;
};
var numObj = new MyNumber();
console.log(numObj * 2); // 优先调用 valueOf
在上述代码中,numObj * 2 是一个数值乘法操作,因此 valueOf 被优先调用并返回 789,最终结果为 1578。如果 valueOf 被移除,引擎将调用 toString 返回的 "456",并将其转换为数字 456 进行计算,结果为 912。
基于 Date 对象输入的具体问题
Date 对象在 JavaScript 中是一个特例,它的 valueOf 和 toString 调用顺序与常规对象相反。在进行默认转换(如 == 比较或 + 拼接)时,Date 对象优先调用 toString,其次才是 valueOf。这是为了符合用户习惯,因为日期通常更倾向于以字符串形式展示。这一行为可以通过 ToPrimitive 算法中的 hint 参数来解释,Date 对象在 hint 为 default 时被视为 hint 为 string。


















