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?
5 Answers
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
toStringmethod.- If the
resultis a primitive, returnresult, else go to Step 2.
- If the
- If available, execute the
valueOfmethod.- If the
resultis 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:
-
4There is a third "way", if you call this:
new String(value)on any value, it will always return a string object. Commented Dec 31, 2016 at 20:31 -
1@Herbertusz
new String({toString: null})throws aTypeError. Commented Jul 10, 2019 at 6:59 -
With the addition of Symbols
String()and+ ''now have a fairly significant difference.String(Symbol())will run, butSymbol() + ''will throw an error (and Symbol() will pass a falsey guard, unlike null and undefined, sox && (x + '')can now throw).– yeerkCommented Aug 6, 2019 at 14:51 -
1Looks like null doesn't have toString and valueOf methods, but String(null) returns 'null' without throwing error. Special behaviour? Commented Nov 4, 2021 at 14:29
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.
-
3I've never seen a null pointer exception in javascript... where did you see that? Commented Oct 15, 2010 at 18:59
-
-
@no, @casablanca Fixed. I'm used to Java. @mykhal How does that look?– JonathanCommented Oct 15, 2010 at 19:07
-
-
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.
-
2
''+valuemight not produce the same result asString(value)ifvaluehas both atoString()method and avalueOf()method. For example ifvalue = {toString(){return "Hello World!"}, valueOf(){return 3}}, thenString(value)will be"Hello World!"but''+valuewill be3. This is because the+operator looks forvalueOfbeforetoString, whereasString(...)only looks fortoString. Commented Sep 1, 2022 at 10:04
I just tried this with ES6 and found out that for String() to look at valueOf() inside of the object, the object has to have toString() method. If the object does not have toString() then console returns '[object Object]' regardless of having valueOf() or not. So in the the first "step", we always have to have toString() regardless, else String() method wouldn't look at valueOf.
Please check this:
let obj = {
name:'b',
age:22,
valueOf: function(){
return 'heeee';
}
}
String(obj); // prints '[object Object]'
On the other hand,
let obj = {
name:'b',
age:22,
toString:null,
valueOf: function(){
return 'heeee';
}
}
String(obj); // prints 'heeee'
let obj = {
name: 'b',
age: 22,
valueOf: function() {
return 'heeee';
}
}
console.log(String(obj));
let obj2 = {
name: 'b',
age: 22,
toString: null,
valueOf: function() {
return 'heeee';
}
}
console.log(String(obj2));
-
Abstract Operation is working under the cover. If the value to be converted is an Object, ToPrimitive Abstract operation is first called. Which calls toString or valueOf. If the object is capable of being converted into more than 1 primitive types then Hint is passed. In above, object is String Object so toString will be called. If it returns the primitive value, then convert to string (if not already string). If returns a non primitive value then valueOf is called to get primitive value (to convert into string if not string via ToString Abstract method) otherwise Type Error is thrown.– SadiqCommented Jul 28, 2023 at 12:16
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