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

Max*_*kyi 8 javascript

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

var o = {};
o.toString = function() {return 1};
1+ o; // 2
Run Code Online (Sandbox Code Playgroud)

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

Eri*_*AND 10

我想这个解释在ECMA-262规范的 8.6.2.6章节中:

8.6.2.6 [DefaultValue]

[...]

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

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

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

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

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

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

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

由于您的对象未实现valueOf,因此使用toString.


Yeh*_*wad 9

这一切都取决于提示.当你使用1 + o它是一个数字提示因为+操作数所以它肯定会使用valueOf之前toString.

如果提示是String,则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
Run Code Online (Sandbox Code Playgroud)


Yur*_*nko 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
Run Code Online (Sandbox Code Playgroud)

长读:

  1. 加成
  2. ToPrimitive