Why is document.all falsy?

dom, javascript

Solution

Disclaimer: I’m the guy who tweeted the question that led to this thread :) It was a question I would ask and answer in my Front-Trends talk. I wrote that tweet 5 minutes before going on stage.

The question I was asking is the following.

The ECMAScript spec defines `ToBoolean()` as follows:

As you can see, all non-primitive objects (i.e. all objects that aren’t a boolean, a number, a string, `undefined`, or `null`) are truthy as per the spec. However, in the DOM, there is one exception to this — a DOM object that is falsy. Do you know which one that is?

The answer is `document.all`. The HTML spec says:

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:

The user agent must act as if the `ToBoolean()` operator in JavaScript converts the object returned for `all` to the `false` value.

The user agent must act as if, for the purposes of the `==` and `!=` operators in JavaScript, the object returned for `all` is equal to the `undefined` value.

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

These requirements are a willful violation of the JavaScript specification current at the time of writing (ECMAScript edition 5). The JavaScript specification requires that the `ToBoolean()` operator convert all objects to the `true` value, and does not have provisions for objects acting as if they were `undefined` for the purposes of certain operators. 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.

So, `document.all` is the only official exception to this ECMAScript rule. (In Opera, `document.attachEvent` etc. are falsy too, but that’s not specced anywhere.)

The above text explains why this was done. But here’s an example code snippet that’s very common on old web pages, and that will illustrate this further:

if (document.all) {
  // code that uses `document.all`, for ancient browsers
} else if (document.getElementById) {
  // code that uses `document.getElementById`, for “modern” browsers
}

Basically, for a long time `document.all` was used in this way to detect old browsers. Because `document.all` is tested first though, more modern browsers that offer both properties, would still end up in the `document.all` code path. In modern browsers, we’d prefer to use `document.getElementById`, of course, but since most browsers still have `document.all` (for other backwards compatibility reasons) the `else` would never be accessed if `document.all` was truthy. Had the code been written differently, this wouldn’t be a problem:

if (document.getElementById) {
  // code that uses `document.getElementById`, for “modern” browsers
} else if (document.all) {
  // code that uses `document.all`, for ancient browsers
}

But sadly, a lot of existing code does it the other way around.

The simplest fix for this problem is to simply make `document.all` be falsy in browsers that still mimic it.

Problem

`document.all` is a non-primitive object in the DOM that is falsy. For example, this code doesn't do anything: ``` if (document.all) { alert("hello"); } ``` Can someone explain why this is?

Original source

Related problems