document.all
是 DOM 中的一个非原始对象,它是虚假的。
例如,这段代码不做任何事情:
if (document.all) {
alert("hello");
}
有人可以解释这是为什么吗?
document.all
是 DOM 中的一个非原始对象,它是虚假的。
例如,这段代码不做任何事情:
if (document.all) {
alert("hello");
}
有人可以解释这是为什么吗?
免责声明: 我是在推特上发布导致该线程的问题的人 :)这是我会在我的前沿趋势演讲中提出和回答的问题。我在上台前 5 分钟写了那条推文。
我问的问题如下。
ECMAScript 规范定义ToBoolean()
如下:
如您所见,所有非原始对象(即所有不是布尔值、数字、字符串、undefined
或null
的对象)按照规范都是真实的。然而,在 DOM 中,有一个例外——一个虚假的 DOM 对象。你知道那是哪一个吗?
答案是document.all
。HTML 规范说:
该
all
属性必须返回一个HTMLAllCollection
根节点Document
,其过滤器匹配所有元素。为 all 返回的对象有几个异常行为:
用户代理必须像
ToBoolean()
JavaScript 中的运算符将返回的对象转换为all
值false
一样。对于JavaScript中的
==
and运算符,用户代理必须表现得好像返回的对象等于该 值。!=
all
undefined
用户代理必须采取行动,以便 JavaScript 中的运算符在应用于返回的对象时
typeof
返回字符串。'undefined'
all
这些要求故意违反了撰写本文时的 JavaScript 规范(ECMAScript 第 5 版)。JavaScript 规范要求
ToBoolean()
运算符将所有对象转换为true
值,并且没有规定对象的行为就好像它们是undefined
为了某些运算符的目的一样。这种违规的动机是希望与两类遗留内容兼容:一种使用存在document.all
作为检测遗留用户代理的一种方式,一种只支持那些遗留用户代理并使用document.all
对象而不首先测试其存在.
所以,document.all
是这个 ECMAScript 规则的唯一官方例外。(在 Operadocument.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
}
但可悲的是,很多现有的代码都是相反的。
解决这个问题的最简单方法是document.all
在仍然模仿它的浏览器中简单地设置为 falsy。
现在有一个用于对象的[[IsHTMLDDA]] 内部槽:
[[IsHTMLDDA]] 内部插槽可能存在于实现定义的对象上。具有 [[IsHTMLDDA]] 内部槽的对象的行为类似于
undefined
在 ToBoolean 和 Abstract Equality Comparison 抽象操作中以及在用作运算符的操作数时typeof
。
HTML 标准也已更新,为实现HTMLAllCollection
接口的对象添加了该内部插槽:
实现 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");
};
现代浏览器不再实现这个过时的东西。它是由 IE 引入的,但大多数其他“填充”它是兼容的。
为了使浏览器检测成为可能(在过去,您可以通过测试来区分 IE 和 NN )同时支持 document.all 语法,其他浏览器制作了返回未定义document.all
的“奇怪”实现。typeof document.all
Opera> document.all
// prints the array-like object
Opera> typeof document.all
"undefined"
Opera> Boolean(document.all)
false
在 FF 放弃对它的支持之前,它还表现出此消息中所述的奇怪行为。您可以在Mozilla 错误 #412247中找到更多内部信息。
W3C 邮件列表存档中也有一个很长的线程,以http://lists.w3.org/Archives/Public/public-html/2009Jun/0546.html开头
简而言之,就是让这两个代码示例都能正常工作。浏览器必须这样做才能使旧网页继续工作。
// Internet Explorer
if (document.all) {
useActiveX()
}
// Netscape Navigator
else {
useOldButStillWorkingCode()
}
document.all.output.innerHTML = 'Hello, world!'