带有id的DOM树元素是否成为全局变量?

Koo*_*Inc 341 javascript dom global-variables identifier getelementbyid

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

对于DOM树中具有ID的给定HTMLElement,可以使用其ID作为变量名来检索div.所以对于一个喜欢的div

<div id="example">some text</div>
Run Code Online (Sandbox Code Playgroud)

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

alert(example.innerHTML); //=> 'some text'
Run Code Online (Sandbox Code Playgroud)

要么

alert(window['example'].innerHTML); //=> 'some text'
Run Code Online (Sandbox Code Playgroud)

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

bob*_*nce 380

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

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

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

通常认为不好的做法是省略var,以及依赖于在window全局上可见的命名元素.坚持document.getElementById,更广泛支持,更少模糊.如果您不喜欢打字,可以使用较短的名称编写一个简单的包装函数.无论哪种方式,使用id-to-element查找缓存都没有意义,因为浏览器通常会优化getElementById调用以使用快速查找; 所有你得到的是元素更改id或从文档中添加/删除时出现的问题.

歌剧复制IE,然后WebKit的加入进来,现在都穿上命名元素的以前不标准,实践document特性,并把他们的先前IE-只有实践window 标准化的HTML5,其方法是将文件和规范每浏览器作者给我们带来了可怕的做法,使它们永远成为网络的一部分.所以Firefox 4也会支持这个.

什么是'命名元素'?任何带有一个id东西,以及name用于"识别"目的的任何东西:即形式,图像,锚点和其他一些东西,但不是name属性的其他无关实例,例如表单输入字段中的控件名称,参数名称<param>或元数据类型<meta>.'识别' name是应该避免的id.

  • "应该避免使用`name`"的一个例外是`<input>`,其中`name`属性在形成表单提交的键值对的键中起着关键作用. (18认同)
  • 为什么!?我们能做些什么来阻止这种疯狂吗?我的函数通过引用元素重新定义,我花了一个小时来调试.:( (12认同)
  • FYI Firefox只在进入怪癖模式时执行此操作. (7认同)
  • 这是一个明确的答案,谢谢.省略document.getElementById并不是我的想法(事实上,我现在使用xpath来查找元素/元素属性).我偶然发现了这个(糟糕的)命名项目的做法,并对它的来源感到好奇.你回答得足够多了; 现在我们知道为什么它也可以在Chrome(webkit)中找到. (5认同)
  • @yahelc:这正是我正在做的区别."在表单输入字段中没有像名字一样的其他用途......就像控制名字一样..." (4认同)
  • 我们能否为这篇文章提供一些 TLDR,或者更新到 2016 年?是否会像“将‘命名元素’暴露给全局/窗口/文档范围对于浏览器实现来说是一个坏主意。应该避免依赖此功能。[TODO:对于命名元素要避免的建议是什么名称冲突?例如,我可以命名我的 DIV#location 吗?]'? (2认同)
  • 有趣的事实:这些全局属性也延续到浏览器扩展代码的“独立”执行上下文中,并且 LastPass 扩展获得了[完全拥有](https://bugs.chromium.org/p/project-zero /issues/detail?id=1225) 由于这个惊人的功能 (2认同)
  • 我同意使用 document.getElementById 是最佳实践,但是我会测试性能,看看以不同的方式这样做是否有好处。它看起来确实是现代浏览器中性能最高的。这是我用来评估这一点的简单测试:https://jsben.ch/AZD81 (2认同)

TJ *_*oll 49

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

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

然而,像Firefox 14,火狐现在支持命名访问window的标准模式对象也是如此.他们为什么改变这个?事实证明,仍有很多网站在标准模式下依赖此功能.微软甚至发布了一个营销演示,阻止了该演示在Firefox中运行.

Webkit最近考虑了相反的做法,window仅将对象的命名访问权限降级为怪癖模式.他们通过与Gecko相同的推理决定反对它.

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

为什么?本文总结了很多关于全局变量为什么不好的原因.简而言之,拥有一堆额外的全局变量会导致更多错误.假设您不小心输入了a的名称var并碰巧键入了id一个DOM节点,SURPRISE!

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

  • IE错误地使name表单元素(输入,选择等)可以访问属性的值.
  • Gecko和Webkit错误地不会<a>通过其name属性访问标签.
  • Gecko错误地处理了多个具有相同名称的命名元素(它返回对单个节点而不是引用数组的引用).

如果你尝试在边缘情况下使用命名访问,我相信还有更多.

正如其他答案中所提到的那样,document.getElementById用来获取对DOM节点的引用id.如果需要通过其name属性使用来获取对节点的引用document.querySelectorAll.

请不要在您的站点中使用命名访问来传播此问题.如此多的网络开发人员浪费时间试图追踪这种神奇的行为.我们确实需要采取行动并让渲染引擎在标准模式下关闭命名访问.从短期来看,它会破坏一些做坏事的网站,但从长远来看,这将有助于推动网络向前发展.

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

  • @jeremyfoster除非"代码牛仔"是指使用和传播糟糕的开发人员不友好的实现的人,我强烈反对. (4认同)
  • 只是注意到"它不应该被使用"这一前提的明显警告.也就是说,"它不应该被使用,除非你恰好是一个代码牛仔." 代码牛仔只是为了它. (3认同)
  • 一个好牛仔的一个标志是许多不同意.但现在我就像哲学牛仔或类似的东西. (2认同)

Nic*_*ver 20

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

document.getElementById('example').innerHTML
Run Code Online (Sandbox Code Playgroud)

IE喜欢在全局命名空间中混合使用元素name ID属性,因此最好明确指出你想要获得的内容.


Bek*_*caj 8

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

答案是肯定的!

这就是它的工作原理,这就是 W3C 开始引入 ID 的原因。: 解析脚本环境中的 HTML 标记的 ID 成为其对应的 DOM 元素句柄。

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

在 Netscape Navigator 4.7 惨败之后,他们的开发人员都去渗透了 W3C,而他们的同事正在以错误的做法和滥用示例取代 Web。强制使用和重用已弃用的 Name 属性 [! 这并不意味着是唯一的] 与 ID 属性相同,这样使用 ID 句柄访问特定 DOM 元素的脚本就会崩溃!

并打破他们做了,因为他们也撰写和发表大量的编码的经验教训和例子[他们的浏览器将不会反正承认]例如 document.all.ElementID.property,而不是ElementID.property至少使其效率低下,更多的开销给浏览器的情况下,它没有简单地打破它HTML 域使用相同的标记(现在 [1996-97],已弃用)名称和标准 ID 属性为其提供相同的标记值。

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

Mosaic Killers [代号为“Mozilla”] 非常生气,他们认为“如果我们失败了,互联网也应该如此”。

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

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

这就是 W3C 变得丑陋并给我们带来了诸如document.getElementById洛可可式这种令人讨厌的洛可可式语法之类的白痴的唯一原因......(......)

  • 因此,在 2021 年,我认为将其用于小型网站和表单是否安全?真正的潜在客户无法提交不使用 document.getElementById() 的表单的百分比是多少?对我来说,在 2021 年,这似乎可以节省大量时间,并且对于所有密集用途来说都可以安全使用吗?只要开发人员确切地知道代码的小级别使用中发生了什么。 (2认同)
  • @agiopnl 他们是通过分配的 ID 访问的!这是 WC3 引入 ID 而不是名称的唯一原因。ID 应该是唯一的。而名字则不然。就像现实生活中一样。 (2认同)

qff*_*qff 6

是的,他们确实这么做了。

\n\n

在 Chrome 55、Firefox 50、IE 11、IE Edge 14 和 Safari 10 中测试
\n并使用以下示例:

\n\n
<!DOCTYPE html>\n<html>\n<head>\n</head>\n<body>\n  <div id="im_not_particularly_happy_with_that">\n    Hello World!\n  </div>\n  <script>\n    im_not_particularly_happy_with_that.innerText = \'Hello Internet!\';\n  </script>\n  <!-- Looking at you W3 HTML5 spec group \xe0\xb2\xa0_\xe0\xb2\xa0 -->\n</body>\n</html>\n
Run Code Online (Sandbox Code Playgroud)\n\n

http://jsbin.com/mahobinopa/edit?html,输出

\n