具有ID的DOM树元素是否会成为全局变量?

本秂侑毒 提交于 2020-03-03 18:18:25

在研究一个简单的HTMLElement包装器的想法时,我偶然发现了Internet Explorer和Chrome的以下内容:

对于DOM树中具有ID的给定HTMLElement,可以使用其ID作为变量名称来检索div。 所以对于像

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

Internet Explorer 8和Chrome中,您可以执行以下操作:

alert(example.innerHTML); //=> 'some text'

要么

alert(window['example'].innerHTML); //=> 'some text'

那么,这是否意味着DOM树中的每个元素都将转换为全局名称空间中的变量? 并且这是否还意味着可以用它代替这些浏览器中的getElementById方法?


#1楼

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

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

但是,从Firefox 14开始, Firefox现在还支持在标准模式下对window对象的命名访问 。 他们为什么要改变这一点? 事实证明,仍有很多站点在标准模式下依赖此功能。 微软甚至发布了一个行销演示 ,阻止了该演示在Firefox中运行。

Webkit最近考虑了相反的做法,仅将window对象上的命名访问权限授予怪癖模式。 他们以与壁虎相同的理由决定反对。

因此,……似乎很疯狂,因为从技术上讲,现在在标准模式下的所有主流浏览器的最新版本中使用此行为都是安全的 。 但是,尽管命名访问似乎有点方便, 但不应使用它

为什么? 关于全局变量为何坏的原因,本文可以总结很多原因。 简而言之,拥有大量额外的全局变量会导致更多错误。 假设您不小心输入了var的名称,而碰巧输入了DOM节点的id ,SURPRISE!

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

  • IE错误地使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/上更详细地讨论。


#2楼

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

document.getElementById('example').innerHTML

IE喜欢在全局名称空间中混合使用具有name ID属性的元素,因此最好明确说明您要获取的内容。


#3楼

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

IE也通过将命名元素添加为window对象的属性来使情况变得更糟。 这是双重不利的,因为现在您必须避免在您想要使用的documentwindow对象(或项目中的任何其他库代码)的任何成员之后命名元素。

这也意味着这些元素作为全局变量可见。 幸运的是,在这种情况下,代码中的任何真实的全局varfunction声明都将它们遮蔽了,因此您不必担心在这里命名,但是如果您尝试使用名称冲突的方式对全局变量进行赋值而忘记了如果将其声明为var ,则在IE中会出现错误,因为它试图将值分配给元素本身。

通常,忽略var以及依赖于在window或全局变量上可见的命名元素是不明智的做法。 坚持使用document.getElementById ,它得到了更广泛的支持,并且不那么模棱两可。 如果您不喜欢键入,则可以使用短名称编写平凡的包装函数。 无论哪种方式,使用id到元素的查找缓存都是没有意义的,因为浏览器通常会优化getElementById调用以使用快速查找。 当元素更改id或从文档中添加/删除元素时,您得到的只是问题。

Opera复制了IE,然后加入了WebKit,现在HTML5 正在 标准化以前未标准化的将命名元素放在document属性中的做法,以及以前仅限IE将其放在window中的做法,HTML5的做法是记录和规范浏览器作者对我们造成的所有可怕行为,使它们永远成为网络的一部分。 因此Firefox 4也将支持此功能。

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


#4楼

是的,他们有。

已在Chrome 55,Firefox 50,IE 11,IE Edge 14和Safari 10中测试
下面的例子:

<!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,输出


#5楼

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

答案是肯定的!

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

但是,Netscape Mozilla拒绝遵循(侵入他们的)W3C,并顽固地使用不推荐使用的Name属性来造成破坏,因此破坏了W3C引入唯一ID所带来的脚本功能和编码便利性。

在Netscape Navigator 4.7惨败之后,他们的开发人员全都去渗透了W3C,而他们的同事却以错误的做法和错误的示例取代了Web。 强制使用和重用已经过时的Name属性[!并不是唯一的]与ID属性相提并论,以便利用ID句柄访问特定DOM元素的脚本会被破坏!

打破他们的做法,因为他们也会编写和发布大量的编码课程和示例(他们的浏览器ElementID.property无法识别它们),例如document.all.ElementID.property而不是ElementID.property ,至少使其效率低下,并给浏览器带来更多开销如果它不是简单地在HTML域上通过使用相同的标记(现在[1996-97],已弃用)和为其提供相同标记值的标准ID属性来将其破坏的话。

他们很容易地说服了当时的绝大多数无知的代码编写爱好者,他们的名字和ID实际上是相同的,除了ID属性更短,因此比古老的Name属性更节省字节和更方便编码。 这当然是骗人的。 或者-在其取代已发表的HTML文章的过程中,说服您需要为标签提供名称和ID的文章,以便脚本引擎可以访问它们。

马赛克杀手[代号“ Mozilla”]非常生气,他们以为“如果我们失败了,互联网也应该如此”。

另一方面,崛起的Microsoft太天真了,他们以为应该保留不推荐使用的标记并标记为删除Name属性,并将其视为唯一标识符的ID来对待,以便他们不会破坏该脚本的脚本功能Netscape学员编码的旧页面。 他们是致命的错误...

而且,返回ID冲突元素的数组集合也不是解决此人为问题的方法。 实际上,它打败了整个目标。

这是唯一的原因W3C的越演越烈,给我们idiocies如document.getElementById和排序的陪同洛可可该死的烦人语法...(...)

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!