I know that when JS tries to represent an object as primitive, it calls valueOf
method on an object. But today I found out that it also calls toString()
method in the same situation:
var o = {};
o.toString = function() {return 1};
1+ o; // 2
Why? If I add valueOf
method then toString
is not called.
I know that when JS tries to represent an object as primitive, it calls valueOf
method on an object. But today I found out that it also calls toString()
method in the same situation:
var o = {};
o.toString = function() {return 1};
1+ o; // 2
Why? If I add valueOf
method then toString
is not called.
3 Answers
Reset to default 10I suppose the explanation lies in 8.6.2.6 chapter of ECMA-262 specification:
8.6.2.6 [DefaultValue]
[...]
When the [[DefaultValue]] method of O is called with hint Number, the following steps are taken:
Call the [[Get]] method of object O with argument "valueOf".
If Result(1) is not an object, go to step 5.
- Call the [[Call]] method of Result(1), with O as the this value and an empty argument list.
If Result(3) is a primitive value, return Result(3).
Call the [[Get]] method of object O with argument "toString".
If Result(5) is not an object, go to step 9.
- Call the [[Call]] method of Result(5), with O as the this value and an empty argument list.
- If Result(7) is a primitive value, return Result(7).
- Generate a runtime error. When the [[DefaultValue]] method of O is called with no hint, then it behaves as if the hint were Number, unless O is a Date object (see section 15.9), in which case it behaves as if the hint were String.
Since your object doesn't implement valueOf, toString is used.
it all depends on the Hint.
when you use 1 + o
it is a number Hint because of the +
operand so it would definitely use valueOf
before toString
.
If the hint is String, then toString
is used before valueOf
. for example try ["o",o].join("=")
All together would be:
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
TL;DR
When ToPrimitive is called with no hint
it acts as if the hint was number
. That defines methods to be called: first valueOf
then toString
. If you haven't defined your own valueOf
it will call Object.prototype.valueOf
that returns this.
BTW in modern browsers you can be more specific about it
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
Long read:
- Addition
- ToPrimitive