Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why isn't Number.toString() being called on a string concatenation operation?

While experimenting with the default behavior of the Object.toString() function, I noticed that string concatenations like the one below predictably call toString() on the target objects:

var x = { toString: () => "one" };
var y = { toString: () => "two" };
var output = 'x is ' + x + ' while y is ' + y;
console.log(output); // writes "x is one while y is two" to the console

However, the same is not observed when toString() is overridden in the prototypes of Number and Boolean, for instance. It's necessary to "force" a toString() call in order to get the desired output:

Number.prototype.toString = () => "42";
Boolean.prototype.toString = () => "whatever you wish";

var a = 1;
console.log('The answer is ' + a); // writes "The answer is 1"
console.log('The answer is ' + a.toString()); // writes "The answer is 42"

var b = true;
console.log('Girl you know it\'s ' + b); // writes "Girl you know it's true"
console.log('Girl you know it\'s ' + b.toString()); // writes "Girl you know it's whatever you wish"

This is consistent across browsers (tested on Chrome, Firefox and Edge) so I presume it's standard behavior. Where is it documented? Is there a list of the standard objects that get special treatment during string concatenations?

like image 778
Humberto Avatar asked Dec 23 '22 08:12

Humberto


2 Answers

JavaScript will freely convert between number primitives and Number Objects.

If you look at the rules for the + operator you will see that it says:

7 Let lprim be ToPrimitive(lval).

and

9 Let rprim be ToPrimitive(rval).

So when dealing with + it will try to work with primitives over objects.

It then has the ToString rule to convert the primitive to a string.

Number See 7.1.12.1.

… which then describes a long special case.


In short:

It converts the value to a primitive and then has special case rules for converting numbers to strings.

This means it doesn't treat it as an Object or call the .toString method that could normally override such rules.

like image 200
Quentin Avatar answered Dec 28 '22 13:12

Quentin


  1. Plus semantics

    • 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.
  2. ToString

    Argument type: Number => Return NumberToString(argument).

  3. NumberToString

    • If m is NaN, return the String "NaN".
    • If m is +0 or -0, return the String "0".
    • If m is less than zero, return the string-concatenation of "-" and ! ToString(-m).
    • If m is +∞, return the String "Infinity".

    • ... You get the idea.

like image 23
H.B. Avatar answered Dec 28 '22 12:12

H.B.