Reputation: 1512
In javascript, when using add sign (+) to concatenate a string and
another variable, that variable will implicitly call its toString
method if it is not a string
. To verify this, I made a constructor called Apple.
function Apple(name) {
this.name = name;
}
Apple.prototype.toString = function() {
console.log('Apple.prototype.toString called.');
return this.name;
};
var apple = new Apple('Thai apple');
var msg = apple + ' tastes good.'
console.log(msg)
It works as I expected: when calculating apple + ' tastes good'
,
Apple.prototype.toString
is called.
Then I did a similar experiment on Number
type.
Number.prototype.num2str = Number.prototype.toString;
Number.prototype.toString = function() {
console.log('new Number.prototype.toString called.');
return this.num2str();
}
var msg = 'num = ' + 123;
console.log(msg);
After running it, I noticed that Number.prototype.toString
is not called.
I'm confused. Why doesn't it work like the previous example?
Upvotes: 1
Views: 903
Reputation: 816790
Why doesn't it work like the previous example?
toString
is only called if the value is an object (but see below). 123
is not an object, it's a primitive (number) value. Converting primitive values to string values follows different rules. See §7.1.12
in the ES2016 spec, and §7.1.12.1
specifically numbers (too long to quote here) for how values are converted to strings.
Primitive values are not coerced to objects when the +
operator is used.
However, even if you'd create a number object it wouldn't work. That's because toString
is not actually called for number objects. Why is that?
When performing addition, the following steps happen:
[...]
5. Let lprim be ? ToPrimitive(lval).
6. Let rprim be ? ToPrimitive(rval).
[...]
Both values are converted to primitive values first before they are converted to a number or a string specifically (a primitive value can be a string, number, boolean, null
or undefined
).
Converting objects to primitive values this way will ultimately calls valueOf
first. Only if the return value of that function is not a primitive value will toString
be called.
Because new Number(123).valueOf()
returns a primitive value, toString
will not be called!
Here is your example adjusted for valueOf
:
Number.prototype.valueOf = function() {
console.log('new Number.prototype.valueOf called.');
return 'something';
}
var msg = 'num = ' + new Number(123);
console.log(msg);
NB: toString
and valueOf
are actually outdated ways of converting objects to strings/numbers/primitives. Since ES6, the new is to call the @@toPrimitve
method of the object. Only if that doesn't exist, toString
or valueOf
will be called (see §7.1.1 ToPrimitive
).
Upvotes: 4