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()
(String
used as a function):
15.5.1.1 String ( [ value ] )
Returns a String value (not a String object) computed by ToString(value). If value is not supplied, the empty String "" is returned.
The ToString
function (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"
Argument Type | Result
Null | "null"
Undefined | "undefined"
This means that String(null)
and String(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:
function MyString(val) {
if (arguments.length === 0) {
return "";
} else if (typeof val === "undefined") {
return "undefined";
} else if (val === null) {
return "null";
} else if (typeof val === "boolean") {
return val ? "true" : "false";
} else if (typeof val === "number") {
// super complex rules
} else if (typeof val === "string") {
return val;
} else {
// return MyString(ToPrimitive(val, prefer string))
}
}
(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:
// Set the String function and constructor.
%SetCode($String, function(x) {
var value = %_ArgumentsLength() == 0 ? '' : TO_STRING_INLINE(x);
if (%_IsConstructCall()) {
%_SetValueOf(this, value);
} else {
return value;
}
});
macros.py:
macro TO_STRING_INLINE(arg) = (IS_STRING(%IS_VAR(arg)) ? arg : NonStringToString(arg));
runtime.js:
function NonStringToString(x) {
if (IS_NUMBER(x)) return %_NumberToString(x);
if (IS_BOOLEAN(x)) return x ? 'true' : 'false';
if (IS_UNDEFINED(x)) return 'undefined';
return (IS_NULL(x)) ? 'null' : %ToString(%DefaultString(x));
}
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.
There is probably just some extra checks and handling for special cases like null
and undefined
.
It's possible to use String as a "safer" toString alternative, as although it still normally calls the underlying toString, it also works for null and undefined.
You might be interested in seeing the Annotated ES5 (which is much more readable than the ECMAScript 5 PDF) which states that: new String([ value ])
http://es5.github.com/#x15.5.2.1 calls [ToString]
http://es5.github.com/#x9.8 (there is a table of the special convertion cases) to convert the value passed to it to a string.
String(null)
creates a string object and passes it a default value of null.
来源:https://stackoverflow.com/questions/10362114/why-does-stringnull-work