带有id的DOM树元素会成为全局属性吗?

在一个简单的HTMLElement包装器的想法中,我偶然发现了下面的Internet Explorer和:

对于DOM树中具有id的给定HTMLElement,可以使用其ID作为变量名或window的属性来检索<div>。对于<div>这样的

<div id="example">some text</div>

Internet Explorer 8和Chrome你可以做:

alert(example.innerHTML); // Alerts "some text".

alert(window["example"].innerHTML); // Alerts "some text".

那么,这是否意味着DOM树中的每个元素被转换为全局对象的属性?它是否也意味着可以在这些浏览器中使用它来替换getElementById方法?

53205 次浏览

在这些情况下,你应该坚持getElementById(),例如:

document.getElementById('example').innerHTML

IE喜欢在全局命名空间中混合带有name 而且 ID属性的元素,所以最好明确你想要得到什么。

应该发生的情况是将“命名元素”作为document对象的表观属性添加。这是一个非常糟糕的主意,因为它允许元素名称与document的真实属性冲突。

IE还将命名元素作为window对象的属性,使情况变得更糟。这是加倍糟糕的,因为现在你必须避免以你(或项目中的任何其他库代码)可能想要使用的documentwindow对象的任何成员命名元素。

这也意味着这些元素作为类全局变量可见。幸运的是,在这种情况下,你的代码中任何真正的全局varfunction声明都会隐藏它们,所以你不需要太担心这里的命名,但如果你试图对一个具有冲突名称的全局变量进行赋值,而你忘记将其声明为var,你将在IE中得到一个错误,因为它试图将值赋值给元素本身。

省略var通常被认为是不好的做法,以及依赖于命名元素在window上可见或作为全局变量。坚持使用document.getElementById,它得到更广泛的支持,且不那么含糊。如果您不喜欢这种类型,您可以编写一个名称较短的普通包装器函数。无论哪种方式,使用id到元素的查找缓存都没有意义,因为浏览器通常会优化getElementById调用以使用快速查找;当元素改变id或从文档中添加/删除时,你所得到的只是问题。

Opera复制了IE,然后WebKit也加入了进来,现在,无论是之前不标准化的将命名元素放在document属性上的做法,还是之前只在IE上使用的将它们放在window上的做法,都是HTML5的 标准化,其方法是记录和标准化浏览器作者强加给我们的每一个可怕的做法,使它们永远成为网络的一部分。Firefox 4也支持这个。

什么是“命名元素”?任何带有id的东西,以及任何用于“识别”目的的带有name的东西:即表单、图像、锚和其他一些东西,但不包括name属性的其他不相关实例,如表单输入字段中的控件名称、<param>中的参数名称或<meta>中的元数据类型。为了支持id,应该避免使用“标识”__abc1。

正如在前面的回答中提到的,这种行为被称为窗口对象上的命名访问。某些元素的name属性值和所有元素的id属性值作为全局window对象的属性可用。这些元素称为命名元素。由于window是浏览器中的全局对象,每个命名的元素都可以作为全局变量访问。

这最初是由Internet Explorer添加的,最终被所有其他浏览器实现,只是为了与依赖此行为的站点兼容。有趣的是,Gecko (Firefox的渲染引擎)选择仅在怪异模式中实现此功能,而其他渲染引擎则将其留在标准模式中。

然而,从Firefox 14开始,标准模式下window对象上的Firefox现在支持命名访问也是如此。他们为什么要改变这个?事实证明,仍然有很多网站在标准模式下依赖这个功能。微软甚至发布营销演示也这样做了,阻止演示在Firefox中工作。

Webkit最近推出了考虑相反的情况,将window对象的命名访问降级为怪异模式。他们反对的理由和壁虎一样。

所以…看起来很疯狂,这个行为现在是在标准模式下,在所有主要浏览器的最新版本中使用在技术上是安全的。但是,虽然命名访问似乎有点方便,它不应该被使用. conf。

为什么?关于为什么使用全局变量不好,很多推理可以在本文中总结出来。简单地说,有一堆额外的全局变量会导致更多的错误。假设你不小心输入了一个var的名字,碰巧输入了一个DOM节点的id,惊喜!

此外,尽管已经标准化,但在浏览器的命名访问实现中仍然存在相当多的差异。

  • IE错误地使表单元素(input, select等)可以访问name属性的值。
  • Gecko和Webkit不正确地使<a>标记不能通过它们的name属性访问。
  • Gecko不正确地处理具有相同名称的多个命名元素(它返回对单个节点的引用,而不是引用数组)。

如果您尝试在边缘情况下使用命名访问,我相信会有更多。

正如在其他答案中提到的,使用document.getElementById通过其id获取对DOM节点的引用。如果你需要通过一个节点的name属性来获取它的引用,请使用document.querySelectorAll

请,请不要在您的站点中使用命名访问来传播这个问题。许多web开发人员浪费时间试图追踪这种神奇的行为。我们真的需要采取行动,让呈现引擎在标准模式下关闭命名访问。在短期内,它将打破一些做坏事的网站,但从长远来看,它将有助于推动网络前进。

如果你感兴趣,我会在我的博客https://www.tjvantoll.com/2012/07/19/dom-element-references-as-global-variables/上详细讨论这一点。

是的,他们有。

在Chrome 55, Firefox 50, IE 11, IE Edge 14和Safari 10中测试

. sh

. sh
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<div id="im_not_particularly_happy_with_that">
Hello World!
</div>
<script>
im_not_particularly_happy_with_that.innerText = 'Hello Internet!';
</script>
<!-- Looking at you W3 HTML5 spec group ಠ_ಠ -->
</body>
</html>

http://jsbin.com/mahobinopa/edit?html,output

这个问题听起来应该是::“带有提供id的HTML标签会成为全局可访问的DOM元素吗?”

答案是肯定的!

这就是它的工作方式,这也是W3C最初引入id的原因。 在解析脚本环境中,HTML标签的ID将成为其对应的DOM元素句柄

然而,Netscape Mozilla拒绝遵守W3C(对他们来说是侵入性的),固执地继续使用已弃用的Name属性来制造混乱,因此破坏了由W3C引入唯一标识符带来的脚本功能和编码便利。

在Netscape Navigator 4.7的惨败之后,他们的开发人员都去了W3C,而他们的同事却用错误的实践和错误的例子取代了Web。强制使用和重用已弃用的Name属性[!这并不意味着是唯一的],与ID属性相同,因此使用ID句柄访问特定DOM元素的脚本将简单地崩溃!

他们还编写并发布了大量的编码课程和示例[他们的浏览器无论如何都不会识别],例如document.all.ElementID.property而不是ElementID.property,至少使其效率低,并给浏览器更多的开销,以防它不简单地在HTML域中使用相同的令牌(现在[1996-97],已弃用)Name和标准ID属性提供相同的令牌值。

他们很容易地说服了——当时——绝大多数无知的代码编写业余爱好者,他们认为Name和ID实际上是一样的,只是ID属性比古代的Name属性更短,因此节省字节,对编码员来说更方便。这当然是一个谎言。或者,在他们已经发布的HTML文章中,让人信服的文章中,您需要为标记提供Name和ID,以便脚本引擎能够访问它们。

马赛克杀手(代号“Mozilla”)非常生气,他们认为“如果我们垮了,互联网也应该垮”。

另一方面,正在崛起的微软是如此天真,他们认为他们应该保留已弃用并标记为删除的Name属性,并将其视为唯一标识符的ID,这样他们就不会破坏Netscape学员编写的旧页面的脚本功能。他们大错特错了……

返回ID冲突元素的数组集合也不是这个人为问题的解决方案。事实上,这违背了整个目的。

这就是W3C变丑的唯一原因,给了我们像document.getElementById这样的白痴,以及伴随而来的该死的洛可可语法之类的… (…)< / p >