在Javascript中,每个对象都有一个valueOf()和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().
这只是它的方式吗?
("x ="+ x)给出"x =值"而不是"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,但这不是这种情况,因为'+'不强制执行任何类型上下文.
在我得到答案之前,这里有一些细节:
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"
一般而言,该toString
功能并非 "胜过" valueOf
.ECMAScript标准实际上很好地回答了这个问题.每个对象都有一个[[DefaultValue]]
属性,可以按需计算.当要求这个属性时,解释器还提供了一个"提示",表示它期望的值.如果提示是String
,则toString
之前使用valueOf
.但是,如果提示是Number
,那么valueOf
将首先使用.请注意,如果只有一个存在,或者它返回非基元,它通常会将另一个作为第二选择.
该+
运营商一直提供的提示Number
,即使第一个操作数是一个字符串值.即使它要求x
它的Number
表示,因为第一个操作数从中返回一个字符串[[DefaultValue]]
,它会进行字符串连接.
如果要保证toString
调用字符串连接,请使用数组和.join("")
方法.
(但是,ActionScript 3.0稍微修改了它的行为+
.如果任一操作数是a String
,它会将其视为字符串连接运算符并String
在调用时使用提示[[DefaultValue]]
.因此,在AS3中,此示例产生"foo,x = foo,foo" = x,foo1,43,x = foo".)