null and undefined don’t have a toString or valueOf method. Afaik using String calls the toString method of its parameter (e.g. String({}) => [object Object]).
Why do String(null) or String(undefined work then? It doesn’t implicitly do Object.prototype.toString.call(null). because that evaluates to [object Null].
[edit]: from the spec ECMA-262/5th edition (page 48). This doesn’t add to clarification, I’d say:
/*
Table 13 — ToString Conversions
-------------------------------------------------------------------------
Argument Type | Result
-------------------------------------------------------------------------
Undefined | "undefined"
Null | "null"
Boolean | If the argument is true, then the result is "true".
... | ...
*/
After reviewing my previous answer, it seems a complete overhaul of my previous answer is necessary. I was way over complicating it, as the short answer is that these are standards-specified special cases.
The specification for
String()(Stringused as a function):The
ToStringfunction (that exists internally, not in userland) is defined as follows (9.8):“The abstract operation ToString converts its argument to a value of type String according to Table 13”
This means that
String(null)andString(undefined)go into this special table of types and just return the string values valued"null"and"undefined".A user-land pseudo-implementation looks something like this:
(Note that this example ignores the constructor case (
new MyString()) and that it uses user-land concepts rather than engine-land.)I got a bit carried away and found an example implementation (V8 to be specific):
string.js:macros.py:runtime.js:The NonStringToString (which is essentially what is of interest), is luckily defined in psuedo-JS-land. As you can see, there is indeed a special case for null/true/false/undefined.