得知了一个很奇特的属性的document.all,在MDN中这样描述它:

document.all is the only falsy object accessible to JavaScript, because it has the [[IsHTMLDDA]] internal slot. This was done because of compatibility with older versions of Internet Explorer.

得知document.all存在的意义就是与旧的浏览器做兼容,是 IE 4.0 及以上版本的专有属性,是一个表示当前文档的所有对象的娄组,不仅包括页面上可见的实体对象,还包括一些不可见的对象,比如 html 注释等等。至于它出现的原因就要从 20 年前浏览器之战说起了。

当时还没有统一的浏览器标准,微软一家独大推出了 IE4 来打压同样流行的网景浏览器 Navigator 4.x,由于这两个浏览器存在巨大差异,也使开发者面临了一个使网页跨浏览器兼容的噩梦。为了能在两种浏览器上运行代码,开发者不得不适配两个浏览器,而便捷高效的方式就是借用document.layerdocument.all,前者网景独有,后者 IE 独有。

code snippetCopyjavascript
// 远古时期的兼容代码,现在已不再适用 document.all ? 'IE' : 'Netscape'

之后标准制定出来后网景浏览器也几乎成为历史了,但历史遗留已经不允许将all这个属性删除了,这将导致许多网页无法正常运行,而它也就成了 W3C 中的一个“特殊”标准,在 MDN 的浏览器兼容图上几乎所有浏览器都有这个属性。至于为什么特殊,下面会解释到。

为何特殊

在上面 MDN 解释注意到:它是唯一一个为假值的对象!在TC39也说明了它的特殊性:

Objects with an [[IsHTMLDDA]] internal slot are never created by this specification. However, the document.all object in web browsers is a host-defined exotic object with this slot that exists for web compatibility purposes. There are no other known examples of this type of object and implementations should not create any with the exception of document.all.

* 下面会说明[[IsHTMLDDA]]的特殊性

可以在浏览器(chrome 105.0.5195.125 arm64)中得到验证:

code snippetCopyjavascript
typeof document.all === 'undefined' // true if (document.all) console.log('access!') // undefined

在 ECMAScript 标准中的ToBoolean(condition)有大致这样的说明:

Argument typeResult
undefinedfalse
nullfalse
booleansame as input
number+0, -0, NaN ? false : true
string"" ? false : true
object(array, Date, Regex, Function...)true

object转化后到布尔值为true,这就是document.all特殊的地方。其实仔细一点可以发现直接在控制台打印它不是undefined,而是一个实现HTMLAllCollection接口的对象的特殊数组。

document_all_in_console

关于HTMLAllCollection的资料在 MDN 上也待补充。在W3C上有较为完整的说明:

HTMLAllCollection 是服务于历史遗留属性 document.all的。其操作方法类似于 HTMLCollection。它可以被当作函数调用来代替属性调用。

code snippetCopyc
[Exposed=Window,LegacyUnenumerableNamedProperties] interface HTMLAllCollection { readonly attribute unsigned long length; getter Element (unsigned long index); getter (HTMLCollection or Element)? namedItem(DOMString name); (HTMLCollection or Element)? item(optional DOMString nameOrIndex); // Note: HTMLAllCollection objects have a custom [[Call]] internal method and an [[IsHTMLDDA]] internal slot. };

在上面 IDL 结构中我们得知HTMLAllCollection内部包含了一个特殊的插槽:[[IsHTMLDDA]],这个插槽解释了为什么document.all会在控制台中出现怪异的行为。在 W3C 中了解到:

实现 HTMLALLCollection 接口的对象(下面称为特殊对象)具有多种异常行为,因为它们具有[[ISHTMLDDA]]内部插槽:

  1. 当给特殊对象执行ToBoolean()操作时将会返回false
  2. 当给特殊对象执行抽象松散比较运算操作(IsLooselyEqual),如果比较对象是undefinednull则返回true抽象严格比较运算操作(IsStrictlyEqual)不受影响;
  3. 当给特殊对象执行typeof操作,则直接返回undefined

我们可以对其进行验证:

code snippetCopyjavascript
// ToBoolean() 操作 Boolean(document.all) // false // 抽象松散比较运算操作 document.all == undefined // true document.all == null // true // 抽象严格比较运算操作 document.all === undefined // false document.all === null // false // typeof 省去

最后,在我寻找资料时看见一个评论:

感觉这样的知识价值不大。

其实我认评判一个知识,并不只是它给你带来的价值,还有探索过程中的收获。

Refer

HTML Standard

TC39

stackoverflow