使用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
对象的属性,使情况变得更糟。 这是非常糟糕的,因为现在您必须避免在document
或window
对象(或者您的项目中的任何其他库代码)的任何成员想要使用的元素之后命名元素。
这也意味着这些元素可以看作是全局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>