带有 id 的 DOM 树元素会成为全局变量吗?

IT技术 javascript dom global-variables getelementbyid identifier
2020-12-16 23:38:52

在研究一个简单的 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这些浏览器中方法?

5个回答

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

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

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

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

Opera 复制了 IE,然后加入了 WebKit,现在,以前未标准化的将命名元素放在document属性上的做法,以及以前仅在 IE 上使用它们的做法window HTML5标准化了,HTML5 的方法是记录和标准化每个浏览器作者强加给我们的可怕做法,使他们永远成为网络的一部分。所以Firefox 4 也将支持这一点。

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

仅供参考 Firefox 只有在进入怪癖模式时才会这样做。
2021-02-06 23:38:52
为什么!?我们能做些什么来阻止这种疯狂?我的函数通过对元素的引用重新定义,我花了一个小时来调试。:(
2021-02-11 23:38:52
@yahelc:这正是我所做的区分。“不是name表单输入字段类似控件名称的其他用途......”
2021-02-13 23:38:52
请注意,出于此目的,Meta 元素不被视为命名元素。多么随意...
2021-03-03 23:38:52
name应避免使用”的一个例外是 with <input>,其中name属性在形成表单提交的键值对的键中起着关键作用。
2021-03-05 23:38:52

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

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

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

Webkit 最近考虑了相反的情况,将window对象上的命名访问降级为quirks 模式。他们根据与 Gecko 相同的推理决定反对它。

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

为什么?在这篇文章中可以总结出很多关于全局变量为什么不好的推理简而言之,拥有一堆额外的全局变量会导致更多的错误。假设您不小心键入了 a 的名称,但var碰巧键入id了 DOM 节点的an ,这让您大吃一惊!

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

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

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

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

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

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

一个好牛仔的标志之一是很多人不同意。但现在我就像一个哲学牛仔或类似的东西。
2021-02-16 23:38:52
只是对“不应使用它”这一前提的明显警告的说明。也就是说,“除非您碰巧是代码牛仔,否则不应使用它。” 代码牛仔们只管去做。
2021-02-24 23:38:52
@jeremyfoster 除非“代码牛仔”是指使用和传播对开发人员不友好的不良实现的人,否则我强烈不同意。
2021-02-24 23:38:52
更多的人应该在访问 DOM 时使用document.querySelectorAlldocument.querySelector+1 表示使用它的好建议。通过选择器访问元素绝对是一个更有效的过程。
2021-03-03 23:38:52

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

document.getElementById('example').innerHTML

IE 喜欢在全局命名空间中混合元素name ID属性,因此最好明确说明您想要获得的内容。

问题应该是:“带有提供 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 年,这似乎可以节省大量时间,并且对于所有密集用途来说都可以安全使用吗?只要开发人员确切地知道在代码的小级别使用中发生了什么。
2021-03-05 23:38:52

是的,他们这样做。


使用以下示例在 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,输出

它如何处理带连字符的变量名称,例如 id='first-name'。我的测试似乎表明它不起作用。
2021-02-08 23:38:52
也在歌剧中。但是,我认为此页面上表达的对这种机制的反对是很好的。
2021-02-24 23:38:52