为什么document.all麻痹?

时间:2012-04-27 11:53:34

标签: javascript dom

document.all是DOM中的一个非原始对象,它是假的。

例如,此代码不执行任何操作:

if (document.all) {
    alert("hello");
}

有人可以解释为什么会这样吗?

5 个答案:

答案 0 :(得分:84)

免责声明: I’m the guy who tweeted the question that led to this thread :)这是我在Front-Trends演讲中提出并回答的问题。我在上台前5分钟写了推文。


我问的问题如下。

ECMAScript规范defines ToBoolean() as follows

ToBoolean(condition), slide from my Front-Trends 2012 talk

正如您所看到的,所有非原始对象(即所有不是布尔值的对象,数字,字符串,undefinednull)都符合规范。但是,在DOM中,有一个例外 - 一个虚假的DOM对象。你知道那是哪一个吗?

答案是document.allThe HTML spec说:

  

all属性必须返回以HTMLAllCollection节点为根的Document,其过滤器与所有元素匹配。

     

为所有人返回的对象有几个不寻常的行为:

     

用户代理必须像JavaScript中的ToBoolean()运算符一样   将为all返回的对象转换为false值。

     

出于==!=的目的,用户代理必须表现得像   JavaScript中的运算符,为all返回的对象等于   undefined值。

     

用户代理必须采用JavaScript中的typeof运算符   应用于返回的对象时返回字符串'undefined'   all

     

这些要求是对JavaScript的故意违反   编写时的规范当前(ECMAScript第5版)。   JavaScript规范要求ToBoolean()运算符   将所有对象转换为true值,并且没有规定   对于对象而言,就好像它们是undefined一样   某些运营商。这种违规行为是出于对欲望的追求   兼容两类遗留内容:一种使用   存在document.all作为检测旧用户代理的方法,以及   一个只支持那些旧版用户代理并使用   document.all对象没有先测试它的存在。

因此,document.all是此ECMAScript规则的唯一官方例外。 (在Opera中,document.attachEvent等也是假的,但在任何地方都没有。)

上述文字解释了为什么这样做了。但这是一个在旧网页上非常常见的示例代码段,这将进一步说明这一点:

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

基本上,很长一段时间document.all以这种方式用于检测旧浏览器。因为首先测试了document.all,所以提供这两种属性的更现代的浏览器仍会以document.all代码路径结束。在现代浏览器中,我们当然希望使用document.getElementById,但由于大多数浏览器仍然具有document.all(出于其他向后兼容性原因),else永远不会被访问document.all if (document.getElementById) { // code that uses `document.getElementById`, for “modern” browsers } else if (document.all) { // code that uses `document.all`, for ancient browsers } 1}}是真的。如果代码的编写方式不同,这不会是一个问题:

document.all

但遗憾的是,很多现有的代码都是相反的。

解决此问题的最简单方法是简单地使{{1}}在仍然模仿它的浏览器中变得虚假。

答案 1 :(得分:6)

ES2019更新

现在有一个[[IsHTMLDDA]] internal slot用于对象:

在实现定义的对象上可能存在[[IsHTMLDDA]]内部插槽。内部插槽带有[[IsHTMLDDA]]的对象在ToBoolean和Abstract Equality比较抽象操作中用作undefined运算符的操作数时,其行为类似于typeof

HTML标准也已更新,可以为实现HTMLAllCollection interface的对象添加该内部插槽:

实现HTMLAllCollection接口的对象是旧版平台对象,具有下面一节中介绍的附加[[Call]]内部方法。它们还具有一个[[IsHTMLDDA]]内部插槽。


在HTML标准的此注释中指定了这种疯狂的原因:

这些特殊行为是由于希望与两类旧内容兼容:一种使用document.all的存在作为检测旧用户代理的方式,另一种仅支持那些旧用户代理,并且使用document.all对象而不先测试其存在。

因此,基本上该标准希望与这两种类型的代码兼容:

  • 代码,用于检查它是否正在Internet Explorer中运行以使用其非标准功能,例如document.all和Activex;

    if (document.all) {
        useActiveXStuff();
    }
    
  • 假定它在Internet Explorer中运行并使用document.all的代码。

    document.all["my-button"].onclick = function () {
        alert("hi");
    };
    

答案 2 :(得分:5)

简而言之,就是让这些代码示例同时工作。浏览器必须这样做才能使旧网页继续工作。

样本1

.save

样本2

// Internet Explorer
if (document.all) {
    useActiveX()
}
// Netscape Navigator
else {
    useOldButStillWorkingCode()
}

答案 3 :(得分:4)

现代浏览器不再实现这个过时的东西。它是由IE推出的,但其他大部分都是" shim"它是兼容的。

为了使浏览器检测成为可能(在过去,你可以在支持document.all语法的同时通过测试document.all告诉IE除N​​N之外),其他浏览器使得#34;怪异的" typeof document.all返回undefined的实现。

Opera> document.all
// prints the array-like object
Opera> typeof document.all
"undefined"
Opera> Boolean(document.all)
false

在FF放弃对它的支持之前,它也显示出this message中所述的奇怪行为。您可以在Mozilla bug #412247找到更多内部内容。

W3C邮件列表存档中还有very long thread,以http://lists.w3.org/Archives/Public/public-html/2009Jun/0546.html

开头

答案 4 :(得分:2)

document.all不是唯一的伪造对象。另一个问题是关于这个,并且作为答案中的小提琴示例显示文档中有许多虚假对象。金额因使用的浏览器而异。

请参阅此问题All objects in JavaScript are truthy per the spec, but in the DOM one non-primitive object is not. Which?

显示文档http://jsfiddle.net/UTNkW/

的所有虚假对象的小提琴