ChatGPT解决这个技术问题 Extra ChatGPT

带有 ID 的 DOM 树元素会成为全局属性吗?

在构思一个简单的 HTMLElement 包装器时,我偶然发现了 Internet Explorer 和 Chrome 的以下内容:

对于 DOM 树中带有 id 的给定 HTMLElement,可以使用其 ID 作为变量名或作为 window 的属性来检索 <div>。所以对于 <div> 喜欢

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

Internet Explorer 8 和 Chrome 中,您可以:

alert(example.innerHTML); // Alerts "some text".

或者

alert(window["example"].innerHTML); // Alerts "some text".

那么,这是否意味着 DOM 树中的每个元素 都被转换为全局对象的属性?这是否也意味着可以在这些浏览器中使用它来替代 getElementById 方法?

另请参阅 Why don't we just use element IDs as identifiers in JavaScript? 了解为什么不应该使用它,以及 Is there a spec that the id of elements be made global variable? 了解它是如何指定的。
@Bergi,声明不这样做的评论现在已经过时甚至无效。因此,我找不到不使用此功能的具体理由。
@EdmundReed您可能想再次阅读链接问题的答案-这仍然是个坏主意:“隐式声明的全局变量”对工具支持不好甚至没有工具支持,并且“导致代码脆弱”。不要将其称为“功能”,下面的答案解释了它是如何成为出于兼容性原因成为标准的一部分的错误。
@Bergi 很公平,你是对的。我仍然认为它是一个非常简洁的功能,并且只是因为人们没有意识到它而被认为是有问题的。这是我设想使用它的方式:codepen.io/esr360/pen/WEavGE?editors=1000#0
@EdmundReed 当然,如果您没有正确分离内容和逻辑,问题就会减少。此外,我建议不要使用内联事件处理程序或在 DOM 元素上安装自定义方法,滥用它们作为命名空间(注意它不是“范围”)。

e
edddd

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

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

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

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

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

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


为什么!?我们能做些什么来阻止这种疯狂吗?我的函数通过对元素的引用重新定义,我花了一个小时来调试。 :(
我们可以为这篇文章提供一些 TLDR,并可能更新到 2016 年吗?会不会像“让'命名元素'暴露于全局/窗口/文档范围对浏览器来说是一个坏主意。应该避免依赖这个特性。[TODO: 避免命名元素的建议是什么?名称冲突?例如,我可以命名我的 DIV#location 吗?]'?
我很想看到性能差异,我认为这个 jsperf.com/global-named-element/1 表明它很戏剧化,除非我遗漏了什么。
有趣的事实:这些全局属性也延续到浏览器扩展代码的“”“隔离”“”执行上下文中,LastPass 扩展由于这个惊人的特性而获得了 fully owned
我同意使用 document.getElementById 是最佳实践,但是我会测试性能以查看以不同方式执行它是否有好处。对于现代浏览器来说,它确实是最高效的。这是我为评估它而运行的简单测试:jsben.ch/AZD81
T
TJ VanToll

如前面的答案所述,此行为称为 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 对象的命名访问权限降级为仅怪癖模式。他们以与壁虎相同的理由决定反对它。

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

为什么?关于为什么global variables are bad,这篇文章可以总结出很多推理。简单地说,拥有一堆额外的全局变量会导致更多的错误。假设您不小心输入了 var 的名称,并且碰巧输入了 DOM 节点的 id,SURPRISE!

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

IE 错误地使表单元素(输入、选择等)可以访问 name 属性的值。

Gecko 和 Webkit 错误地没有使 标记可以通过它们的 name 属性访问。

Gecko 错误地处理了多个具有相同名称的命名元素(它返回对单个节点的引用而不是引用数组)。

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

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

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

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


只是对“不应使用它”的前提的明显警告。也就是说,“除非您碰巧是代码牛仔,否则不应使用它。”代码牛仔就去吧。
@jeremyfoster 除非“代码牛仔”是指使用和传播对开发人员不友好的不良实现的人,否则我强烈反对。
一个好牛仔的标志之一是许多人不同意。但现在我就像哲学牛仔或类似的东西。
访问 DOM 时应该有更多的人使用 document.querySelectorAlldocument.querySelector。 +1 为使用它的好建议。通过选择器访问元素绝对是一个更高效的过程。
@TravisJ 仅当 id 不可用时,否则它以及 getElementsByClassName 等比 getElementById 慢两倍
N
Nick Craver

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

document.getElementById('example').innerHTML

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


B
Bekim Bacaj

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

答案是肯定的!

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

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

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

并且打破他们所做的,因为他们还将编写和发布大量的编码课程和示例 [他们的浏览器无论如何都无法识别],例如 document.all.ElementID.property 而不是 ElementID.property 至少使其效率低下并给浏览器更多开销以防万一'不要简单地通过对(现在 [1996-97],已弃用)名称和标准 ID 属性使用相同的标记来破坏它在 HTML 域中为它提供相同的标记值。

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

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

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

并且返回 ID 冲突元素的数组集合也不能解决这个故意的人为问题。实际上它破坏了整个目的。

这是 W3C 变得丑陋并给我们带来诸如 document.getElementById 之类的白痴以及伴随的那种该死的洛可可式烦人语法的唯一原因...(...)


所以在 2021 年,我认为将其用于小型网站和表单是否安全?无法提交不使用 document.getElementById() 的表单的真正潜在客户的百分比是多少?对我来说,在 2021 年,这似乎可以节省大量时间,并且对于所有密集型目的来说可以安全使用吗?只要开发人员确切地知道代码的小级别使用中发生了什么。
这很有趣,我也不喜欢洛可可代码。我不太了解整个历史。在 getElementById 之前如何访问元素?
@agiopnl 他们是通过分配给他们的 ID 访问的!这是 WC3 引入 ID 而非名称的唯一原因。 ID 应该是唯一的。而名称不是。就像在现实生活中一样。
q
qff

是的,他们有。

通过以下示例在 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,output


也在歌剧中。但是,我认为在此页面上表达的对这种机制的反对意见很好。
它如何处理连字符的变量名,例如 id='first-name'。我的测试似乎表明它不起作用。
@AdamCarr 您可以通过 window 对象访问它们:window["first-name"]