skip to Main Content
console.log("12"+ {"x":"1",toString(){return 10;},valueOf(){return 90}});

In the above expression why toString() method is not called? As per the algorithm if either the left or right side there is string then we call ToString() with hint as "String" for another side and if hint is "String" then the toString() method will be called first and then the valueOf() method. But the above expression is given answer as "1290" mean valueOf() is called.

Algorithm for additive expression: –

12.8.3The Addition Operator ( + )
NOTE
The addition operator either performs string concatenation or numeric addition.
12.8.3.1Runtime Semantics: Evaluation
AdditiveExpression:AdditiveExpression+MultiplicativeExpression
Let lref be the result of evaluating AdditiveExpression.
Let lval be ? GetValue(lref).
Let rref be the result of evaluating MultiplicativeExpression.
Let rval be ? GetValue(rref).
Let lprim be ? ToPrimitive(lval).
Let rprim be ? ToPrimitive(rval).
If Type(lprim) is String or Type(rprim) is String, then
Let lstr be ? ToString(lprim).
Let rstr be ? ToString(rprim).
Return the string-concatenation of lstr and rstr.
Let lnum be ? ToNumber(lprim).
Let rnum be ? ToNumber(rprim).
Return the result of applying the addition operation to lnum and rnum. See the Note below 12.8.5.

ToString rules: –

7.1.12ToString ( argument )
The abstract operation ToString converts argument to a value of type String according to Table 11:

Table 11: ToString Conversions

ToString conversion table:

According to the ToString Conversion table if there is object then hint "String" will be used.

Please help me out in this problem why valueOf() method is preferred.

2

Answers


  1. As I read the spec,
    13.8.1 The Addition Operator ( + ) specifies this in terms of ApplyStringOrNumericBinaryOperator where

    • lval is "12"
    • opText is +
    • rval is {"x":"1",toString(){return 10;},valueOf(){return 90}})

    As I see it, rprim := ToPrimitive(rval) there ends up invoking OrdinaryToPrimitive(..., "number"), which prefers valueOf to toString.

    Login or Signup to reply.
  2. There’s a note at the bottom of the section 7.1.1 ToPrimitive (input [, PreferredType]) that states

    When ToPrimitive is called with no hint, then it generally behaves as if the hint were Number. However, objects may over-ride this behaviour by defining a @@toPrimitive method. Of the objects defined in this specification only Date objects (see 20.3.4.45) and Symbol objects (see 19.4.3.5) over-ride the default ToPrimitive behaviour. Date objects treat no hint as if the hint were String.

    Which is why you’re seeing the results of calling valueOf() instead of toString(). It also mentions that we can override this behaviour too so that toString() is called:

    var obj = {"x":"1",toString(){return 10;},valueOf(){return 90}};
    obj[Symbol.toPrimitive] = function(){ return this.toString()};
    
    console.log("12" + obj);

    This now behaves as you originally expected and calls toString() and outputs 1210

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search