为什么 document.all 有时像一个对象,有时又不像一个对象

document.all 奇怪的地方在于它是一个数组(其实是对象),但是类型却是 undefined。

先看控制台代码

>>> document.all
HTMLAllCollection[1009]  // 控制台打印出一个数组
>>> document.all[0]
<html>...</html> // 第一个元素是 html 标签,看起来很像一个数组
>>> typeof document.all
'undefined' // 咦,居然不是 object?
>>> if(document.all){console.log('document.all 为真')}else{console.log('document.all 为假')}
document.all 为假 

我第一次看到 document.all 的时候也很惊讶,怎么会有这么奇葩的对象。

用各个浏览器测试一下结果如下:

所有浏览器都支持用 document.all[index] 或者 document.all[id] 获取标签 但是 typeof document.all,在 IE 10 以下的值为 ‘object’,在其他浏览器的值均为 ‘undefined’ 为何会这样?那我们就要从很久很久以前说起了。多久呢,大概20年前。

那个时候,浏览器刚刚出现,很多功能不完善,比如 document.getElementById,都有很多浏览器不支持。甚至连 W3C 都还没制定出 Web 标准,这个时候 IE 4(我擦我都没见过 IE 4)推出了一些 API,只有 IE 4 支持,其中就包括我们今天说 document.all,它比 document.getElementById 要好用一些,比如你可以用 document.all[‘topbar’] 来获取元素,所以那个时候很多程序员会些这样的代码:

if(document.all){
  // IE 4 代码
  document.all['topbar']
  ...
}else if(document.getElementById){
  // 其他浏览器代码
  document.getElementById('topbar')
}

甚至某些程序员直接认为 document.all 为真的浏览器,就是 IE。也就是这样:

if(document.all){
   // IE
}else{
   // 非 IE
}

其他浏览器(网景)觉得 IE 4 有的功能,我也要有才行。于是也加上 document.all,功能一样,可以获取元素。

但是呢,其他浏览器又不想被某些程序员认为是 IE,于是 typeof document.all 的值定为 undefined。

有人说 W3C 标准出来后,为什么浏览器不把 document.all 纠正过来,去掉或者变成一个正常的对象都可以啊。

太天真了,如果浏览器这么做了,那么当时世界上会有很多页面 JS 代码都不能正常运行,到时候用户只会怪浏览器不给力,然后卸载掉浏览器。

浏览器厂商才不想冒这样的风险。

于是,最终,我们在所有浏览器上得到了一个类型为 undefined 的 document.all,只有 IE 10 以下,然后保留着 IE 4 的行为。

不过 document.all 现在已经被弃用了,大家不要再使用它了。用 document.getElementById 或者 document.querySelector 就好 :)

本文只是讲 document.all 吗?不。

现在的前端新人,对浏览器的演化过程并没有任何体会,以为浏览器天生就是按照 Web 标准实现的。发现 IE 不兼容就指责 IE。

浏览器也是软件,浏览器也会犯错,而且浏览器是一直在发展的。

有时间,可以看看浏览器的历史。