document.all
是DOM中的一个非原始对象,它是假的。
例如,此代码不执行任何操作:
if (document.all) {
alert("hello");
}
有人可以解释为什么会这样吗?
答案 0 :(得分:84)
免责声明: I’m the guy who tweeted the question that led to this thread :)这是我在Front-Trends演讲中提出并回答的问题。我在上台前5分钟写了推文。
我问的问题如下。
ECMAScript规范defines ToBoolean()
as follows:
正如您所看到的,所有非原始对象(即所有不是布尔值的对象,数字,字符串,undefined
或null
)都符合规范。但是,在DOM中,有一个例外 - 一个虚假的DOM对象。你知道那是哪一个吗?
答案是document.all
。 The 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)
现在有一个[[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)
简而言之,就是让这些代码示例同时工作。浏览器必须这样做才能使旧网页继续工作。
.save
// Internet Explorer
if (document.all) {
useActiveX()
}
// Netscape Navigator
else {
useOldButStillWorkingCode()
}
答案 3 :(得分:4)
现代浏览器不再实现这个过时的东西。它是由IE推出的,但其他大部分都是" shim"它是兼容的。
为了使浏览器检测成为可能(在过去,你可以在支持document.all语法的同时通过测试document.all
告诉IE除NN之外),其他浏览器使得#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不是唯一的伪造对象。另一个问题是关于这个,并且作为答案中的小提琴示例显示文档中有许多虚假对象。金额因使用的浏览器而异。
的所有虚假对象的小提琴