3

I was just trying something and found this:

If you call String(n) inside custom toString, it calls itself and throws error Maximum Call Stack exceeded,

JSFiddle

Number.prototype.toString = function() {
  return String(this)
}

var a = 10;
try {
  a.toString()
} catch (err) {
  console.log(err.message)
}

but if you call directly var b = String(a), it does not call toString function.

JSFiddle

Number.prototype.toString = function(){
  console.log(this);
  return '' + this;
}

var a = 10;
a.toString();

Note: I know above snippet is also throwing same error, but I have checked on Node, chrome - JSFiddle and Firefox - JSFiddle and it is consistent. var b = String(a) does not call number.toString(), so does '' + this. This is some optimisation in Stack snippet thats calling number.toString() on ''+this.

So my question is, what am I missing? Why is this weird behaviour?

Codor
  • 17,447
  • 9
  • 29
  • 56
Rajesh
  • 24,354
  • 5
  • 48
  • 79
  • @Downvoters, I respect you perspective, but if you think, something is wrong with the post, please share your comment. Just voting it down will not help anyone. – Rajesh Aug 10 '17 at 06:10

2 Answers2

4

Actual numbers invoke an internal method to convert them to string and their output is not affected by valueOf and toString, unless they are called explicitly.

So why is toString called in the first place then?

This is because in "sloppy" (non-strict) mode, the value of this will be converted to its object form (i.e. equivalent of new Number(10)) before being passed to String(this) or '' + this.

(For this reason, you might not see the difference between these two ways in normal applications where strict mode is used.)

As this is an object, both String() and the + addition operator will attempt to convert the object into a string. This is usually done by calling either obj.toString or obj.valueOf.

As for why String(this) fails but '' + this does not, the String function calls toString on the object before calling valueOf.

However, when you use the addition (+) operator, the order of valueOf and toString is reversed.

Qantas 94 Heavy
  • 15,750
  • 31
  • 68
  • 83
  • Not sure about "*the value of this will be converted to its object form…*. I think it's the second part, `String(value)` will call `value.toString`, so if its *toString* method than calls *String*, recursion occurs. See [*ECMA-262 §21.1.1.1*](http://ecma-international.org/ecma-262/7.0/index.html#sec-string-constructor-string-value). – RobG Nov 28 '16 at 07:07
  • @RobG: what I meant was that the reason `toString` is called in the first place is that `String()` on the object form of the number. I'll try and clarify what I've said. – Qantas 94 Heavy Nov 28 '16 at 07:17
  • Cool. Actually, reading more closely, ECMA-262 doesn't specify calling toString in the [*algorithm for ToString(number)*](http://ecma-international.org/ecma-262/7.0/index.html#sec-tostring-applied-to-the-number-type), it might just be how it's implemented. – RobG Nov 28 '16 at 07:18
  • @Qantas94Heavy You are correct. A small query though, in second approach, `'' + this`, in `non strict mode`, `this` should be interpreted as `new Number(10)`. right? – Rajesh Nov 28 '16 at 07:37
  • @Qantas94Heavy Then why does `''+this` works but `String(this)` doesn't – Rajesh Nov 28 '16 at 15:02
  • @Rajesh: see last sentence. As `valueOf` has not been overridden, that will return the number primitive `10`, which is then converted using internal algorithm to string. – Qantas 94 Heavy Nov 28 '16 at 15:04
  • @Qantas94Heavy Thanks! – Rajesh Nov 28 '16 at 15:06
0

May be you should use call/apply.

Number.prototype.toString = function() {
  console.log(this)
  return String(this)
}

var a = 10;
try {
  a.toString.call()
  console.log(a)
} catch (err) {
  console.log(err.message)
}

reason I think is The reason to use JS .call() method?

Community
  • 1
  • 1
Amit Jamwal
  • 629
  • 1
  • 6
  • 16
  • Hey, objective of question is understanding why this is happening. Also just a pointer, doing `.call` without `this` will erase context. – Rajesh Nov 28 '16 at 07:26