Note: the comment on the right side is the return value of the left side statement.
String('foo') // foo
JSON.stringify('foo') // "foo"
'foo'.toString() // foo
String({}) // [object Object]
JSON.stringify({}) // {}
{}.toString() // [object Object]
String(null) // null
JSON.stringify(null) // null
null.toString() // Cannot read property 'toString' of null
String(undefined) // undefined
JSON.stringify(undefined) // undefined
undefined.toString() // Cannot read property 'toString' of undefined
null and undefined are not object. Ok null is but it should not be. Nevertheless both lack a toString method, hence the: Cannot read property 'toString'.
const obj = {
baz: 'baz',
toString: function () { return 'foo'; },
valueOf: function () { return 'bar'; }
};
String(obj) // foo
JSON.stringify(obj) // {"baz:"baz}
obj.toString() // foo
obj + 'qux' // barqux
const arr = [obj, 'qux'];
arr[0] + arr[1] // fooqux
String function calls the toString method behind the scene.+ operator the concatenation uses the valueOf method.[obj, 'qux'] is calling the toString method.obj.toString = null;
String(obj) // bar
JSON.stringify(obj) // {"baz:"baz,"toString":null}
obj.toString() // obj.toString is not a function
The toString method is not available so the String function falls back to the valueOf method.
obj.valueOf = null;
String(obj) // Cannot convert object to primitive value
JSON.stringify(obj) // {"baz:"baz,"toString":null,"valueOf":null}
obj.toString() // obj.toString is not a function
None of the needed methods are here, it throws.
const obj = {
baz: 'baz',
toString: function () { return 'foo'; },
valueOf: function () { return 'bar'; }
};
obj.valueOf = null;
obj + 'qux' // fooqux
const arr = [obj, 'qux'];
arr[0] + arr[1] // fooqux
Funny enough, or not, the concatenation with the + operator uses toString as a fallback if valueOf is not available.
It's the exact opposite behavior as with the string conversion by the String function.
Source: http://www.adequatelygood.com/Object-to-Primitive-Conversions-in-JavaScript.html