Stephen Leppik Stephen Leppik - 21 days ago 4
Javascript Question

Why is document.all defined but typeof document.all returns "undefined"?

I was doing some research on JavaScript's

typeof
operator, and stumbled across the following weirdness:


Exceptions



All current browsers expose a non-standard host object
document.all
with type Undefined.

typeof document.all === 'undefined';


Although the specification allows custom type tags for non-standard exotic objects, it requires those type tags to be different from the predefined ones. The case of
document.all
having type tag
'undefined'
must be classified as an exceptional violation of the rules.


(Source)

I set up the following in my browser to test it:

console.log("typeof: " + typeof document.all);
console.log("toString: " + document.all);


It yielded:

typeof: undefined
toString: [object HTMLAllCollection]


So why is
document.all
like this? Since
document.all
is an object (defined in my browser), shouldn't
typeof
return
"object"
, not
"undefined"
?

Answer

Take a look at this one from Html Spec

The all attribute must return an HTMLAllCollection rooted at the Document node, whose filter matches all elements.

The object returned for all has several unusual behaviors:

  1. The user agent must act as if the ToBoolean abstract operation in JavaScript returns false when given the object returned for all.

  2. The user agent must act as if the Abstract Equality Comparison algorithm, when given the object returned for all, returns true when compared to the undefined and null values. (Comparisons using the Strict Equality Comparison algorithm, and Abstract Equality comparisons to other values such as strings or objects, are unaffected.)

  3. The user agent must act such that the typeof operator in JavaScript returns the string "undefined" when applied to the object returned for all.

The third case is yours.

The rationale for this is compatibility with code designed for old browsers, as explained in a note in the specification:

This violation is motivated by a desire for compatibility with two classes of legacy content: one that uses the presence of document.all as a way to detect legacy user agents, and one that only supports those legacy user agents and uses the document.all object without testing for its presence first.

Hope it will make sense for you.