What's the difference between String(value) vs value.toString()
Javascript has lot's of "tricks" around types and type conversions so I'm wondering if these 2 methods are the same or if there is some corner case that makes them different?
Solution 1:
They are not completely the same, and actually, the String constructor called as a function (your first example), will at the end, call the toString
method of the object passed, for example:
var o = { toString: function () { return "foo"; } };
String(o); // "foo"
On the other hand, if an identifier refers to null
or undefined
, you can't use the toString
method, it will give you a TypeError
exception:
var value = null;
String(null); // "null"
value.toString(); // TypeError
The String
constructor called as a function would be roughly equivalent to:
value + '';
The type conversion rules from Object-to-Primitive are detailed described on the specification, the [[DefaultValue]]
internal operation.
Briefly summarized, when converting from Object-to-String, the following steps are taken:
- If available, execute the
toString
method.- If the
result
is a primitive, returnresult
, else go to Step 2.
- If the
- If available, execute the
valueOf
method.- If the
result
is a primitive, returnresult
, else go to Step 3.
- If the
- Throw
TypeError
.
Given the above rules, we can make an example of the semantics involved:
var o = {
toString: function () { return "foo"; },
valueOf: function () { return "bar"; }
};
String(o); // "foo"
// Make the toString method unavailable:
o.toString = null;
String(o); // "bar"
// Also make the valueOf method unavailable:
o.valueOf = null;
try {
String(o);
} catch (e) {
alert(e); // TypeError
}
If you want to know more about this mechanism I would recommend looking at the ToPrimitive
and the ToString
internal operations.
I also recommend reading this article:
- Object-to-Primitive Conversions in JavaScript
Solution 2:
value.toString()
will cause an error if value
is null or undefined. String(value)
should not.
For example:
var value = null;
alert(value.toString());
will fail because value == null
.
var value = null;
alert(String(value));
should display a message reading "null" (or similar), but it will not crash.
Solution 3:
String(value)
should have the same result as value.toString()
in every case, except for values without properties like null
or undefined
. ''+value
will produce the same result.
Solution 4:
String() [the constructor call] is basically calling the .toString()
.toString() and String() can be called on primitive values(number,boolean,string) and basically will do nothing special:
true => 'true'
false => 'false'
17 => '17'
'hello' => 'hello'
But calling these functions on objects is where things gets interesting:
if the object has it's own .toString() function it will be called when ever you need this object to be treated as a string(explicitly/implicitly)
let obj = {
myName:"some object",
toString:function(){ return this.myName; }
}
//implicitly treating this obj as a string
"hello " + obj; //"hello some object"
//OR (explicitly)
"hello " + String(obj) //calling the existent toString function
//OR
"hello " + obj.toString(); //calling toString directly
By the way if you want to treat this object as a number it should has a .valueOf() function defined in it.
what if we have both in one object?
if we want to treat this object as a string => use .toString()
if we want to treat this object as a number => use .valueOf()
what if we only have .valueOf() defined?
.valueOf() defined inside the object will be called whether we want to handle the object as a string or as a number