针对一个简单的HTMLElement包装器的想法我偶然发现了以下Internet Explorer和Chrome:
对于DOM树中具有ID的给定HTMLElement,可以使用其ID作为变量名来检索div。所以对于像
这样的div<div id="example">some text</div>
您可以在Internet Explorer 8和Chrome中执行:
alert(example.innerHTML); //=> 'some text'
或
alert(window['example'].innerHTML); //=> 'some text'
那么,这是否意味着 DOM树中的每个元素都转换为全局命名空间中的变量?它是否也意味着可以使用它来替代这些浏览器中的getElementById
方法?
答案 0 :(得分:370)
应该发生的是'命名元素'被添加为document
对象的明显属性。这是一个非常糟糕的主意,因为它允许元素名称与document
的真实属性冲突。
通过添加命名元素作为window
对象的属性,IE使情况变得更糟。这是非常糟糕的,因为现在您必须避免在您(或项目中的任何其他库代码)可能想要使用的document
或window
对象的任何成员之后命名您的元素。 / p>
这也意味着这些元素作为类似全局变量可见。幸运的是,在这种情况下,代码中的任何真正的全局var
或function
声明都会影响它们,因此您不必担心这里的命名,但是如果您尝试对全局进行分配变量与冲突的名称,你忘了声明它var
,你会在IE中得到一个错误,因为它试图将值赋给元素本身。
通常认为忽略var
以及依赖于window
上可见的命名元素或全局变量是不好的做法。坚持document.getElementById
,这是更广泛支持和更少模糊。如果您不喜欢打字,可以使用较短的名称编写一个简单的包装函数。无论哪种方式,使用id-to-element查找缓存都没有意义,因为浏览器通常会优化getElementById
调用以使用快速查找;当元素发生变化id
或从文档中添加/删除时,你得到的只是问题。
Opera复制IE,然后WebKit加入,现在既有先前未标准化的将命名元素放在document
属性上的做法,以及以前只在IE上放置它们window
的做法是HTML5的being standardised,其方法是记录并标准化浏览器作者对我们造成的每一种可怕做法,使其永远成为网络的一部分。所以Firefox 4也会支持这个。
什么是'命名元素'?任何带有id
的内容,以及name
用于“识别”目的的任何内容:即表单,图片,锚点和其他一些内容,而不是{{1}的其他无关实例}属性,如表单输入字段中的控件名称,name
中的参数名称或<param>
中的元数据类型。 “识别”<meta>
应该避免使用name
。
答案 1 :(得分:46)
如前面的答案所述,此行为称为named access on the window object。某些元素的name
属性值和所有元素的id
属性值可用作全局window
对象的属性。这些被称为命名元素。由于window
是浏览器中的全局对象,因此每个命名元素都可以作为全局变量访问。
这最初是由Internet Explorer添加的,最终由所有其他浏览器实现,只是为了兼容依赖于此行为的网站。有趣的是,Gecko(Firefox的渲染引擎)选择仅在quirks mode中实现此功能,而其他渲染引擎则以标准模式启用它。
但是,从Firefox 14开始,window
对象也是标准模式下的Firefox now supports named access。他们为什么改变这个?事实证明,仍有很多网站在标准模式下依赖此功能。微软甚至released a marketing demo确实阻止了这个演示在Firefox中运行。
Webkit最近considered the opposite,将window
对象的命名访问权限仅限于怪癖模式。他们通过与Gecko相同的推理决定反对它。
所以...疯狂,因为在标准模式的所有主流浏览器的最新版本中,这种行为现在在技术上是安全的。但是,虽然命名访问看起来有点方便,但不应该使用。
为什么呢?很多推理可以在本文中总结为什么global variables are bad。简而言之,拥有一堆额外的全局变量会导致更多错误。假设您不小心输入了var
的名称,并且碰巧输入了一个DOM节点的id
,SURPRISE!
此外,尽管标准化,但浏览器的命名访问实现仍然存在很多差异。
name
属性的值。<a>
属性访问name
个标记。如果您尝试在边缘情况下使用命名访问,我相信还有更多。
如其他答案中所述,使用document.getElementById
通过其id
获取对DOM节点的引用。如果您需要通过name
属性使用document.querySelectorAll
来获取对节点的引用。
请不要在您的站点中使用命名访问来传播此问题。许多网络开发人员浪费时间试图追踪这种神奇的行为。我们确实需要采取行动并让渲染引擎在标准模式下关闭命名访问。从短期来看,它会破坏一些做坏事的网站,但从长远来看,这将有助于推动网络向前发展。
如果您有兴趣,我会在我的博客上更详细地讨论这个问题 - https://www.tjvantoll.com/2012/07/19/dom-element-references-as-global-variables/。
答案 2 :(得分:20)
在这些情况下你应该坚持getElementById()
,例如:
document.getElementById('example').innerHTML
IE喜欢在全局命名空间中混合使用name
和 ID
属性的元素,因此最好明确说明您要获取的内容。
答案 3 :(得分:3)
是的,他们确实这样做了。
在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>
答案 4 :(得分:2)
听起来应该是这样的问题:“具有提供的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元素的脚本会被破坏!
打破他们的做法,就像编写和发布大量的编码课程和示例一样(它们的浏览器无法识别),例如document.all.ElementID.property
而不是ElementID.property
,至少可以使其效率低下,并提供如果浏览器没有使用相同的令牌(现在[1996-97],已弃用)和为其提供相同令牌值的标准ID属性,而不仅仅是在HTML域将其破坏,则将增加浏览器的开销。
他们很容易地说服了当时的绝大多数无知的代码编写爱好者,他们的名字和ID实际上是相同的,只是ID属性更短,因此节省了字节,比古老的编码器更方便编码名称属性。这当然是骗人的。或者-在其取代已发表的HTML文章的过程中,说服您需要为标签提供名称和ID的文章,以便脚本引擎可以访问它们。
“马赛克杀手”(代号“ Mozilla”)非常生气,他们以为“如果我们失败了,互联网也应该如此”。
另一方面,崛起的Microsoft太天真了,以为他们应该保留不推荐使用的内容并标记为删除Name属性,并将其视为唯一标识的ID,这样他们才不会破坏Netscape受训者编码的旧页面的脚本功能。他们是致命的错误...
返回ID冲突元素的数组集合也不是解决此人为问题的方法。实际上,它打败了整个目标。
这是W3C变得丑陋并为我们提供了诸如document.getElementById
之类的惯用语以及伴随的洛可可式令人讨厌的语法的唯一原因...
(...)