valueOf() vs. toString() in Javascript

2022-08-30 05:07:16

在Javascript中,每个对象都有一个值Of()和toString()方法。我本来以为每当需要字符串转换时都会调用toString()方法,但显然它被valueOf()所取代。

例如,代码

var x = {toString: function() {return "foo"; },
         valueOf: function() {return 42; }};
window.console.log ("x="+x);
window.console.log ("x="+x.toString());

将打印

x=42
x=foo

这让我感到倒退..例如,如果x是一个复数,我会希望 valueOf() 给我它的大小,但是每当我想转换为字符串时,我都会想要类似“a + bi”的东西。而且我不想在暗示字符串的上下文中显式调用 toString()。

事实就是这样吗?


答案 1

(“x=”+x)给出“x=value”而不是“x=tostring”的原因如下。在计算“+”时,javascript首先收集操作数的基元值,然后根据每个基元的类型决定是否应应用加法或串联。

所以,这就是你认为它的工作原理

a + b:
    pa = ToPrimitive(a)
    if(pa is string)
       return concat(pa, ToString(b))
    else
       return add(pa, ToNumber(b))

这就是实际发生的事情

a + b:
    pa = ToPrimitive(a)
    pb = ToPrimitive(b)*
    if(pa is string || pb is string)
       return concat(ToString(pa), ToString(pb))
    else
       return add(ToNumber(pa), ToNumber(pb))

也就是说,toString 应用于 valueOf 的结果,而不是原始对象。

有关进一步的参考,请查看 ECMAScript 语言规范中的第 11.6.1 节加法运算符 ( + )。


*在字符串上下文中调用时,ToPrimitive 调用 toString,但这里不是这种情况,因为 '+' 不强制任何类型上下文。


答案 2

在我得到答案之前,这里有一些更详细的信息:

var x = {
    toString: function () { return "foo"; },
    valueOf: function () { return 42; }
};

alert(x); // foo
"x=" + x; // "x=42"
x + "=x"; // "42=x"
x + "1"; // 421
x + 1; // 43
["x=", x].join(""); // "x=foo"

功能通常不会被“超越”。ECMAScript 标准实际上很好地回答了这个问题。每个对象都有一个属性,该属性是按需计算的。当请求此属性时,解释器还会提供它期望的值类型的“提示”。如果提示为 ,则在 之前使用 。但是,如果提示是 ,则将首先使用。请注意,如果只存在一个,或者它返回一个非基元,它通常会将另一个称为第二选择。toStringvalueOf[[DefaultValue]]StringtoStringvalueOfNumbervalueOf

运算符总是提供提示,即使第一个操作数是字符串值。即使它要求它的表示,由于第一个操作数从 返回一个字符串,它也会执行字符串连接。+NumberxNumber[[DefaultValue]]

如果要保证为字符串串联调用,请使用数组和方法。toString.join("")

(但是,ActionScript 3.0 稍微修改了 + 的行为。如果任一操作数是字符串,它将将其视为字符串串联运算符,并在调用 [[DefaultValue]] 时使用提示字符串。因此,在 AS3 中,此示例生成“foo, x=foo, foo=x, foo1, 43, x=foo”。