javascript 为什么文件都是假的?

kmbjn2e3  于 2023-03-16  发布在  Java
关注(0)|答案(5)|浏览(493)

document.all是DOM中的一个非原语对象,它是错误的。
例如,以下代码不执行任何操作:

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

有人能解释一下这是为什么吗?

xcitsw88

xcitsw881#

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

我问的问题如下。
ECMAScript规范将ToBoolean()定义如下:

正如您所看到的,所有非原语对象(即所有不是布尔值、数字、字符串、undefinednull的对象)都符合规范。但是,在DOM中,有一个例外-DOM对象是falsy。您知道是哪一个吗?
答案是document.all。HTML规范规定:
all属性必须返回以Document节点为根的HTMLAllCollection,其筛选器与所有元素匹配。
为all返回的对象有几个异常行为:
用户代理必须按照JavaScript中的ToBoolean()运算符将all返回的对象转换为false值的方式工作。
用户代理必须按照如下方式工作:就JavaScript中的==!=运算符而言,为all返回的对象等于undefined值。
用户代理必须执行以下操作:JavaScript中的typeof运算符在应用于为all返回的对象时返回字符串'undefined'
这些要求故意违反了编写本文时的JavaScript规范JavaScript规范要求ToBoolean()运算符将所有对象转换为true值,并且不具有为了某些操作符的目的而使对象表现得好像它们是X1 M19 N1 X一样的规定。这种违规行为的动机是希望与两类旧内容兼容:一种使用X1 M20 N1 X的存在作为检测传统用户代理的方式,另一种仅支持那些传统用户代理并且使用X1 M20 N1 X对象而不首先测试其存在。
因此,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(出于向后兼容的原因),如果document.all是真的,那么else将永远不会被访问。

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。

vngu2lb8

vngu2lb82#

ES 2019更新

现在有一个IsHTMLDDA内部插槽用于对象:
IsHTMLDDA内部槽可能存在于实现定义的对象上。具有IsHTMLDDA内部槽的对象在ToBoolean和Abstract Equality Comparison抽象运算中以及用作typeof运算符的操作数时的行为类似于undefined
HTML标准也已更新,为实现HTMLAllCollection接口的对象添加了内部槽:
实现HTMLAllCollection接口的对象是具有附加Call内部方法的旧平台对象,该方法在下面的部分中介绍。它们还具有IsHTMLDDA内部槽。
这种疯狂的原因在HTML标准的注解中有详细说明:
这些特殊行为的动机是希望与两类传统内容兼容:一种使用X1 M3 N1 X的存在作为检测传统用户代理的方式,另一种仅支持那些传统用户代理并且使用X1 M4 N1 X对象而不首先测试其存在。
因此,基本上标准希望与这两种类型的代码兼容:

  • 检查是否在Internet Explorer中运行以使用其非标准功能(如document.all和Activex)的代码;
if (document.all) {
    useActiveXStuff();
}
  • 假定在Internet Explorer内部运行并使用document.all的代码。
document.all["my-button"].onclick = function () {
    alert("hi");
};
oyxsuwqo

oyxsuwqo3#

简而言之,就是让这两个代码样本都能工作,浏览器必须这样做,这样旧的网页才能继续工作。

样品1

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

样品2

document.all.output.innerHTML = 'Hello, world!'
bjp0bcyl

bjp0bcyl4#

现代的浏览器不再实现这个过时的东西了,它是由IE引入的,但大多数其他浏览器都用它来兼容。
为了使浏览器检测成为可能(回到过去,你可以通过测试document.all来区分IE和NN),同时支持document.all语法,其他浏览器做出了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开头

y4ekin9u

y4ekin9u5#

其他的答案已经很好地解释了为什么document.all会这样运行。
但是我非常好奇想知道更多关于历史视角的东西,document.all从何而来,为什么现代浏览器支持它到今天?
所以,我做了一些研究来了解更多,这是我的发现。
document.all最初是在Internet Explorer 4中引入的,它的主要用途是通过ID访问元素,如下所示:

var element = document.all[id]

后来,W3C将document.getElementById标准化为通过ID获取元素的方法。
然而,由于IE多年来一直拥有最大的市场份额,许多网站只是继续使用document.all而没有进行测试。
其中一些网站是相当受欢迎的,他们会打破浏览器以外的IE。
因此,人们开始讨论在其他浏览器中添加对document.all的支持,以便使用document.all的网站能够在这些浏览器中工作。
为了给予你一些讨论内容的例子,这里有两个来自bugzilla的讨论:

所以,最后,其他浏览器开始实现document.all
然而,由于网站使用document.all来检测IE,因此使用if语句,如下所示:

if (document.all) {
  // Use proprietary Internet Explorer APIs
}

为了防止其他浏览器被误检测为Internet Explorer,W3C将document.all标准化为一个伪对象,其行为类似于undefined。
所以,截至2023年,document.all仍然在所有主流浏览器中受支持,你可能会问为什么?可能是因为他们希望旧网站能正常工作。
我在YouTube上做了一个2分钟的视频,介绍document.all及其历史,如果你对此感兴趣,可以看看:https://youtu.be/KFasyUpmoss

相关问题