Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does JS call `toString` method when object is added to a number

Tags:

javascript

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.

like image 276
Max Koretskyi Avatar asked Jul 10 '16 10:07

Max Koretskyi


People also ask

Why is toString automatically called?

The toString method is automatically called when something is printed using println. It also gets called when an object is concatenated with a String and can be called explicitly when required.

Is toString method automatically called?

toString() gets invoked automatically. Object. toString() 's default implementation simply prints the object's class name followed by the object's hash code which isn't very helpful. So, one should usually override toString() to provide a more meaningful String representation of an object's runtime state.

Is toString automatically called JavaScript?

toString . For user-defined Function objects, the toString method returns a string containing the source text segment which was used to define the function. JavaScript calls the toString method automatically when a Function is to be represented as a text value, e.g. when a function is concatenated with a string.

Why toString method is used in JavaScript?

The toString() method is used internally by JavaScript when an object needs to be displayed as a text (like in HTML), or when an object needs to be used as a string. Normally, you will not use it in your own code.


3 Answers

I 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:

  1. Call the [[Get]] method of object O with argument "valueOf".

  2. If Result(1) is not an object, go to step 5.

  3. Call the [[Call]] method of Result(1), with O as the this value and an empty argument list.
  4. If Result(3) is a primitive value, return Result(3).

  5. Call the [[Get]] method of object O with argument "toString".

  6. If Result(5) is not an object, go to step 9.

  7. Call the [[Call]] method of Result(5), with O as the this value and an empty argument list.
  8. If Result(7) is a primitive value, return Result(7).
  9. 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.

like image 163
Eric MORAND Avatar answered Oct 03 '22 12:10

Eric MORAND


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
like image 35
Yehia Awad Avatar answered Oct 03 '22 12:10

Yehia Awad


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:

  1. Addition
  2. ToPrimitive
like image 30
Yury Tarabanko Avatar answered Oct 03 '22 13:10

Yury Tarabanko