当对象添加到数字时,为什么JS调用`toString`方法

时间:2016-07-10 10:53:01

标签: javascript

我知道当JS尝试将对象表示为原始对象时,它会在对象上调用valueOf方法。但今天我发现它在同样的情况下也调用toString()方法:

var o = {};
o.toString = function() {return 1};
1+ o; // 2

为什么呢?如果我添加valueOf方法,则不会调用toString

3 个答案:

答案 0 :(得分:10)

我想解释的原因在于ECMA-262 specification的8.6.2.6章节:

  

8.6.2.6 [DefaultValue]

[...]

当使用提示编号调用O的[[DefaultValue]]方法时,将执行以下步骤:

  1. 使用参数" valueOf"调用对象O的[[Get]]方法。

  2. 如果结果(1)不是对象,请转到步骤5.

  3. 调用Result(1)的[[Call]]方法,使用O作为此值和空参数列表。
  4. 如果Result(3)是原始值,则返回Result(3)。

  5. 使用参数" toString"调用对象O的[[Get]]方法。

  6. 如果结果(5)不是对象,请转到步骤9。

  7. 调用Result(5)的[[Call]]方法,使用O作为此值和空参数列表。
  8. 如果Result(7)是原始值,则返回Result(7)。
  9. 生成运行时错误。 当没有提示调用O的[[DefaultValue]]方法时,它的行为就好像提示是Number, 除非O是Date对象(参见15.9节),在这种情况下,它的行为就像提示是String一样。
  10. 由于您的对象没有实现valueOf,因此使用toString。

答案 1 :(得分:9)

一切都取决于提示。 当您使用1 + o时,由于+操作数,它是一个数字提示,因此在valueOf之前肯定会使用toString

如果提示是字符串,则在toString之前使用valueOf。例如,尝试["o",o].join("=")

一起将是:

var o = {};
o.toString = function() {return 1};
o.valueOf= function(){return 2};
1 + o; // 1+2=3 ==> it takes valueOf value
["o",o].join("") //o1 ==> it takes toString value

答案 2 :(得分:5)

<强> TL; DR

当调用ToPrimitive而没有hint时,它就像提示是number一样。这定义了要调用的方法:首先valueOf然后toString。如果您尚未定义自己的valueOf,则会调用Object.prototype.valueOf来返回此内容。

BTW在现代浏览器中你可以更具体地了解它

const a = {
   [Symbol.toPrimitive]: function(hint) {
       console.log(hint);
       return {
          'default': 1,
          'number': 2,
          'string': 'three'
       }[hint]
   }
}

console.log(a + 1); //default, 2
console.log(+a + 1); //number, 3
console.log(`${a} + one`); //string, three + one

长读:

  1. Addition
  2. ToPrimitive
相关问题