使用ID做DOM树元素成为全局variables?

工作在一个简单的HTMLElement包装的想法我偶然发现以下Internet Explorer和Chrome :

对于在DOM树中具有ID的给定HTMLElement,可以使用其ID作为variables名来检索div。 所以对于一个div

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

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

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

要么

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

那么,这是否意味着DOM树中的每个元素都被转换为全局命名空间中的一个variables? 这是否也意味着可以使用这个替代这些浏览器中的getElementById方法?

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

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

这也意味着这些元素可以看作是全局variables。 幸运的是,在这种情况下,代码中的任何真正的全局variables或function声明都会影响它们,所以您不必担心在这里命名太多,但是如果尝试使用冲突名称对全局variables进行赋值,并且忘记了声明它的var ,你会在IE中得到一个错误,因为它试图将值分配给元素本身。

通常认为不好的做法是省略var ,以及依赖在window上可见的命名元素或全局variables。 坚持document.getElementById ,这是更广泛的支持和不太模糊。 如果你不喜欢打字,你可以写一个简短的包装函数。 无论哪种方式,使用ID到元素的查找caching没有意义,因为浏览器通常会优化getElementById调用来使用快速查找。 所有你得到的是当元素改变id或者被添加/从文档中移除时的问题。

Opera拷贝了IE,然后WebKitjoin了,现在,既有标准化的将document属性放在名称元素上的做法,以及以前只用IE浏览器的做法,都被 HTML5 标准化 ,HTML5的做法是logging和标准化浏览器作者对我们造成的每一个可怕的做法,使他们永远成为networking的一部分。 所以Firefox 4也会支持这个。

什么是“命名元素”? 任何带有id东西,任何带有name东西都是用来“识别”的目的,即表单,图像,锚点和其他一些东西,而不是其他name属性的无关实例,比如表单input字段中的控件名称, <param>参数名称或<meta>元数据types。 “识别”的name是应该避免有利于id

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

这最初由Internet Explorer添加,最终由所有其他浏览器实现,只是为了与依赖此行为的网站兼容。 有趣的是,Gecko(Firefox的渲染引擎)select只在怪癖模式下实现,而其他渲染引擎将其置于标准模式下。

但是,从Firefox 14开始, Firefox现在也支持标准模式下window对象的命名访问 。 他们为什么改变这个? 原来在标准模式下仍然有很多网站依赖这个function。 微软甚至发布了一个营销演示 ,防止演示在Firefox中运行。

最近Webkit 认为是相反的 ,只把window对象的命名访问降级为怪癖模式。 他们用与壁虎相同的推理来反对它。

所以……看起来这种行为在标准模式下在所有主stream浏览器的最新版本中使用现在在技术上是安全的 。 但是,虽然命名访问看起来有些方便, 但不应该使用

为什么? 在这篇文章中,可以总结出很多理由来说明全局variables为什么不好 。 简而言之,拥有一堆额外的全局variables会导致更多的错误。 让我们假设你不小心input了一个var的名字,碰巧键入了一个DOM节点的id ,惊喜!

另外,尽pipe被标准化,但在浏览器的命名访问实现方面仍然存在不less差异。

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

而且我敢肯定还有更多,如果你尝试在边缘情况下使用命名访问。

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

请不要通过在您的网站中使用命名访问来传播此问题。 许多networking开发人员浪费时间来追踪这种神奇的行为。 我们真的需要采取行动,让渲染引擎在标准模式下closures命名访问。 在短期内,它会打破一些网站做坏事,但从长远来看,这将有助于networking向前发展。

如果您有兴趣,可以在我的博客上详细讨论这个问题 – http://tjvantoll.com/2012/07/19/dom-element-references-as-global-variables/

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

 document.getElementById('example').innerHTML 

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

是的,他们这样做。

在Chrome 55,Firefox 50,IE 11,IE Edge 14和Safari 10中进行testing
用下面的例子:

 <!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